Setup

library(ggplot2)
 警告メッセージ: 
 options(opt) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
library(dplyr)
library(tidyr)
library(purrr)

library(SummarizedExperiment)
source("/home/guestA/n70275b/work/rscripts/geomNorm.R") #ITO
#source("/home/ito_mirror/n70275b/work/rscripts/geomNorm.R")

# Helper function
#ggpoints <- function(x,...) 
#  ggplot(x,...) + geom_point(size=3,stroke=1) +
#  ggrepel::geom_text_repel(size=4) + theme_minimal() + mycolor

## ラベルあり
ggpoints <- function(x,...) 
  ggplot(x,...) + geom_point(stroke=1) +
  ggrepel::geom_text_repel(size=4) + theme_minimal() + mycolor

## ラベルなし
#ggpoints <- function(x,...) 
#  ggplot(x,...) + geom_point(stroke=1) + theme_minimal() + mycolor


print(Sys.Date())
[1] "2020-08-31"
print(sessionInfo(),locale=FALSE)
R version 4.0.1 (2020-06-06)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux

Matrix products: default
BLAS/LAPACK: /usr/local/intel2018_up1/compilers_and_libraries_2018.0.128/linux/mkl/lib/intel64_lin/libmkl_intel_lp64.so

attached base packages:
 [1] grid      stats4    parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] corrplot_0.84                             Hmisc_4.4-1                               Formula_1.2-3                            
 [4] survival_3.2-3                            lattice_0.20-41                           stringr_1.4.0                            
 [7] hrbrthemes_0.8.0                          ggrepel_0.8.2                             ggpubr_0.4.0.999                         
[10] gplots_3.0.4                              DESeq2_1.28.1                             GGally_2.0.0                             
[13] vcd_1.4-7                                 BiocParallel_1.22.0                       Matrix_1.2-18                            
[16] SummarizedExperiment_1.18.2               DelayedArray_0.14.1                       matrixStats_0.56.0                       
[19] motifmatchr_1.10.0                        org.Mm.eg.db_3.11.4                       TxDb.Mmusculus.UCSC.mm10.knownGene_3.10.0
[22] org.Hs.eg.db_3.11.4                       TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2   GenomicFeatures_1.40.1                   
[25] AnnotationDbi_1.50.3                      Biobase_2.48.0                            ChIPseeker_1.24.0                        
[28] clusterProfiler_3.16.1                    BSgenome.Mmusculus.UCSC.mm10_1.4.0        ggsignif_0.6.0                           
[31] chromVAR_1.10.0                           purrr_0.3.4                               RColorBrewer_1.1-2                       
[34] ggsci_2.9                                 readr_1.3.1                               tidyr_1.1.2                              
[37] dplyr_1.0.2                               ggplot2_3.3.2                             TFBSTools_1.26.0                         
[40] BSgenome_1.56.0                           rtracklayer_1.48.0                        Biostrings_2.56.0                        
[43] XVector_0.28.0                            GenomicRanges_1.40.0                      GenomeInfoDb_1.24.2                      
[46] IRanges_2.22.2                            S4Vectors_0.26.1                          BiocGenerics_0.34.0                      

loaded via a namespace (and not attached):
  [1] rappdirs_0.3.1              R.methodsS3_1.8.1           bit64_4.0.5                 knitr_1.29                 
  [5] R.utils_2.10.1              rpart_4.1-15                data.table_1.13.0           KEGGREST_1.28.0            
  [9] RCurl_1.98-1.2              generics_0.0.2              cowplot_1.0.0               lambda.r_1.2.4             
 [13] RSQLite_2.2.0               europepmc_0.4               bit_4.0.4                   enrichplot_1.8.1           
 [17] xml2_1.3.2                  httpuv_1.5.4                assertthat_0.2.1            DirichletMultinomial_1.30.0
 [21] viridis_0.5.1               xfun_0.16                   hms_0.5.3                   evaluate_0.14              
 [25] promises_1.1.1              fansi_0.4.1                 progress_1.2.2              caTools_1.18.0             
 [29] dbplyr_1.4.4                readxl_1.3.1                igraph_1.2.5                DBI_1.1.0                  
 [33] geneplotter_1.66.0          htmlwidgets_1.5.1           futile.logger_1.4.3         reshape_0.8.8              
 [37] ellipsis_0.3.1              backports_1.1.9             annotate_1.66.0             biomaRt_2.44.1             
 [41] vctrs_0.3.4                 abind_1.4-5                 withr_2.2.0                 ggforce_0.3.2              
 [45] triebeard_0.3.0             checkmate_2.0.0             GenomicAlignments_1.24.0    prettyunits_1.1.1          
 [49] cluster_2.1.0               DOSE_3.14.0                 lazyeval_0.2.2              seqLogo_1.54.3             
 [53] crayon_1.3.4                genefilter_1.70.0           pkgconfig_2.0.3             tweenr_1.0.1               
 [57] nnet_7.3-14                 rlang_0.4.7                 lifecycle_0.2.0             miniUI_0.1.1.1             
 [61] downloader_0.4              extrafontdb_1.0             BiocFileCache_1.12.1        cellranger_1.1.0           
 [65] polyclip_1.10-0             lmtest_0.9-37               urltools_1.7.3              carData_3.0-4              
 [69] boot_1.3-25                 zoo_1.8-8                   base64enc_0.1-3             pheatmap_1.0.12            
 [73] ggridges_0.5.2              png_0.1-7                   viridisLite_0.3.0           bitops_1.0-6               
 [77] R.oo_1.24.0                 KernSmooth_2.23-17          blob_1.2.1                  qvalue_2.20.0              
 [81] jpeg_0.1-8.1                rstatix_0.6.0               gridGraphics_0.5-0          CNEr_1.24.0                
 [85] scales_1.1.1                memoise_1.1.0               magrittr_1.5                plyr_1.8.6                 
 [89] gdata_2.18.0                zlibbioc_1.34.0             compiler_4.0.1              scatterpie_0.1.4           
 [93] plotrix_3.7-8               Rsamtools_2.4.0             cli_2.0.2                   htmlTable_2.0.1            
 [97] formatR_1.7                 MASS_7.3-52                 tidyselect_1.1.0            stringi_1.4.6              
[101] forcats_0.5.0               yaml_2.2.1                  GOSemSim_2.14.1             askpass_1.1                
[105] locfit_1.5-9.4              latticeExtra_0.6-29         fastmatch_1.1-0             tools_4.0.1                
[109] rio_0.5.16                  rstudioapi_0.11             TFMPvalue_0.0.8             foreign_0.8-80             
[113] gridExtra_2.3               farver_2.0.3                ggraph_2.0.3                digest_0.6.25              
[117] rvcheck_0.1.8               BiocManager_1.30.10         shiny_1.5.0                 pracma_2.2.9               
[121] Rcpp_1.0.5                  car_3.0-9                   broom_0.7.0                 later_1.1.0.1              
[125] httr_1.4.2                  gdtools_0.2.2               colorspace_1.4-1            XML_3.99-0.5               
[129] splines_4.0.1               uwot_0.1.8                  graphlayouts_0.7.0          ggplotify_0.0.5            
[133] plotly_4.9.2.1              systemfonts_0.2.3           xtable_1.8-4                jsonlite_1.7.0             
[137] futile.options_1.0.1        poweRlaw_0.70.6             tidygraph_1.2.0             R6_2.4.1                   
[141] pillar_1.4.6                htmltools_0.5.0             mime_0.9                    glue_1.4.2                 
[145] fastmap_1.0.1               DT_0.15                     fgsea_1.14.0                tibble_3.0.3               
[149] curl_4.3                    gtools_3.8.2                zip_2.1.1                   GO.db_3.11.4               
[153] openxlsx_4.1.5              openssl_1.4.2               Rttf2pt1_1.3.8              rmarkdown_2.3              
[157] munsell_0.5.0               DO.db_2.9                   GenomeInfoDbData_1.2.3      msigdbr_7.1.1              
[161] haven_2.3.1                 reshape2_1.4.4              gtable_0.3.0                extrafont_0.17             
select <- dplyr::select
count <- dplyr::count
rename <- dplyr::rename

BRB mouse CTX result

Parameters

modify here

# Files
# ITO

deftable <- "~/akuwakado/kuwakado/BRBSeq/H3mm18KO_and_H3p3KO_0438/R_server__mouse_H3mm18KO_CTX__190924-/deftable_nucleosomever_BRB_noumi_H3mm18KO_and_H3p3KO_0438_190515-H3mm18KO_CTX_S2-Day0_S3_200523modif.txt"

# カウントには、「/home/ito_mirror/o70578a/akuwakado/kuwakado/BRBSeq/H3mm18KO_and_H3p3KO_0438/190515-H3mm18KO_CTX_S2_trimmed.counts.txt.gz」等を使用するように変更。


use <- quo(sample!="H3mm18KO-Day5-intact-m2") #20200523はこちら
use <- quo((sample!="H3mm18KO-Day5-intact-m2")&(intact_CTX!="intact")) #20200831変更 #こちらにしても、group1_CTX_Day5_H3mm18KO_vs_WTのDEGはほとんど変わらない


# Species specific parameters
species <- "Mus musculus"
biomartann <- "mmusculus_gene_ensembl"
maxchrom <- 19 # 19: mouse, 22: human


# Graphics
# aesthetic mapping of labels

myaes <- aes(colour=WT_KO_intact_CTX, shape=Day, label=f_m) #サイズを変えず#

#type_Doxplus_vs_minus = c("type", "Doxplus", "Doxminus")
#growth_Diff0h_vs_UI = c("growth","Diff0h","UI")


#file   sample  group   group1   WT_KO_intact_CTX   barcode  WT_KO  Day intact_CTX  f_m replicate

#file   sample  group   group1  barcode  WT_KO  Day intact_CTX  f_m replicate


#type,time,intact_CTX, f_m

# color palette of points: See vignette("ggsci")
mycolor <- ggsci::scale_color_aaas()

#mycolor <- ggsci::scale_color_d3("category20") # color palette of points

#myaes2 <- aes(colour=type) #kuwa add
#myaes2 <- aes(colour=growth,shape=type)#kuwa add
#myaes2 <- aes(colour=time,shape=type,size=count) #ラベルな
#myaes2 <- aes(colour=time,shape=intact_CTX,size=type,label=f_m) #ラベルなし
#myaes2 <- aes(colour=WT_KO,shape=intact_CTX,size=f_m,label=Day)


# PCA/UMAP
scalerows <- TRUE # gene-wise scaling (pattern is the matter?)
ntop <- 500 # number of top-n genes with high variance
seed <- 123 # set another number if UMAP looks not good
n_nei <- 6  # number of neighboring data points in UMAP #ここをどうしたらいい?


# DESeq2
#model <- ~groupn+lead #dateも追加
#model <- ~leg + enzyme + leg:enzyme
#model <- ~type+growth#+type:growth
#model <- ~group+lead


#model <- ~group
#model <- ~type+growth+type:growth #これでは相互作用が入っていない
#model <- ~type+growth #これでは相互作用が入っていない
#model <- ~group

model <- ~group1

#fdr <- 0.1 # acceptable false discovery rate
fdr <- 0.2 # acceptable false discovery rate

lfcthreth <- log2(1) # threshold in abs(log2FC)
# controls should be placed in the right
contrast <- list(

  Intercept = list("Intercept"),
  group1_SKM_Day0_H3mm18KO_vs_WT = c("group1", "H3mm18KO_Day0_SKM", "WT_Day0_SKM"),
  group1_CTX_Day5_H3mm18KO_vs_WT = c("group1", "H3mm18KO_Day5_CTX", "WT_Day5_CTX"),
  group1_CTX_Day14_H3mm18KO_vs_WT = c("group1", "H3mm18KO_Day14_CTX", "WT_Day14_CTX")

  #group1_intact_Day5_H3mm18KO_vs_WT = c("group1", "H3mm18KO_Day5_intact", "WT_Day5_intact"),
  #group1_intact_Day14_H3mm18KO_vs_WT = c("group1", "H3mm18KO_Day14_intact", "WT_Day14_intact")

)


sort_mouse <- c(
  "WT-f179-SKM","WT-f870-SKM","WT-m181-SKM",
  "WT-Day5-CTX-f1","WT-Day5-CTX-f2","WT-Day5-CTX-f3","WT-Day5-CTX-m1",
  "WT-Day14-CTX-f1","WT-Day14-CTX-f2","WT-Day14-CTX-f3","WT-Day14-CTX-m1","WT-Day14-CTX-m2",
  "H3mm18KO-f177-SKM","H3mm18KO-f869-SKM","H3mm18KO-m182-SKM",
  "H3mm18KO-Day5-CTX-f1","H3mm18KO-Day5-CTX-f2","H3mm18KO-Day5-CTX-f3","H3mm18KO-Day5-CTX-m1","H3mm18KO-Day5-CTX-m2",
  "H3mm18KO-Day14-CTX-f1","H3mm18KO-Day14-CTX-f2","H3mm18KO-Day14-CTX-f3","H3mm18KO-Day14-CTX-m1","H3mm18KO-Day14-CTX-m2"
  
  #"WT-Day5-intact-f1","WT-Day5-intact-f2","WT-Day5-intact-f3","WT-Day5-intact-m1",
  #"WT-Day14-intact-f1","WT-Day14-intact-f2","WT-Day14-intact-f3","WT-Day14-intact-m1","WT-Day14-intact-m2",
  #"H3mm18KO-Day5-intact-f1","H3mm18KO-Day5-intact-f2","H3mm18KO-Day5-intact-f3","H3mm18KO-Day5-intact-m1",
  #"H3mm18KO-Day14-intact-f1","H3mm18KO-Day14-intact-f2","H3mm18KO-Day14-intact-f3","H3mm18KO-Day14-intact-m1","H3mm18KO-Day14-intact-m2" 
)

Retrieve Biomart

if(!exists("e2g")){
  #ensembl <- biomaRt::useMart("ENSEMBL_MART_ENSEMBL",host="asia.ensembl.org")
  ensembl <- biomaRt::useMart("ENSEMBL_MART_ENSEMBL",host="uswest.ensembl.org")
  mart <- biomaRt::useDataset(biomartann,mart=ensembl)
  e2g <- biomaRt::getBM(attributes=c("ensembl_gene_id","external_gene_name",
    "gene_biotype","chromosome_name"), mart=mart) %>% as_tibble %>%
  rename(
    ens_gene = ensembl_gene_id,
    ext_gene = external_gene_name,
    biotype = gene_biotype,
    chr = chromosome_name
  )
}
annotate <- partial(right_join,e2g,by="ens_gene")

#-----#
nrow(e2g)
[1] 56305
#readr::write_csv(e2g,"ensemble_list_asia_fin200831.csv")
readr::write_csv(e2g,"ensemble_list_uswest_fin200831.csv")

Load counts

def <- readr::read_tsv(deftable) %>% filter(!!use)
Parsed with column specification:
cols(
  file = col_character(),
  sample = col_character(),
  group = col_character(),
  group1 = col_character(),
  WT_KO_intact_CTX = col_character(),
  barcode = col_character(),
  WT_KO = col_character(),
  Day = col_character(),
  intact_CTX = col_character(),
  f_m = col_character(),
  replicate = col_double()
)
print(def)

def$sample
 [1] "WT-Day5-CTX-f1"        "WT-Day5-CTX-f2"        "WT-Day5-CTX-f3"        "WT-Day5-CTX-m1"        "H3mm18KO-Day5-CTX-f1" 
 [6] "H3mm18KO-Day5-CTX-f2"  "H3mm18KO-Day5-CTX-f3"  "H3mm18KO-Day5-CTX-m1"  "H3mm18KO-Day5-CTX-m2"  "WT-Day14-CTX-f1"      
[11] "WT-Day14-CTX-f2"       "WT-Day14-CTX-f3"       "WT-Day14-CTX-m1"       "WT-Day14-CTX-m2"       "H3mm18KO-Day14-CTX-f1"
[16] "H3mm18KO-Day14-CTX-f2" "H3mm18KO-Day14-CTX-f3" "H3mm18KO-Day14-CTX-m1" "H3mm18KO-Day14-CTX-m2" "WT-m181-SKM"          
[21] "H3mm18KO-m182-SKM"     "WT-f179-SKM"           "H3mm18KO-f177-SKM"     "WT-f870-SKM"           "H3mm18KO-f869-SKM"    
length(sort_mouse)
[1] 25
####--- New ---#### (no UMI ?)
# Set reference levels according to the contrast
for(x in keep(contrast,is.character))
  def[[x[1]]] <- relevel(factor(def[[x[1]]]),x[3])

umi <- def$file %>% unique %>% tibble(file=.) %>% 
  dplyr::mutate(data=map(file,readr::read_tsv,progress=FALSE)) %>%
  unnest() %>% dplyr::rename(barcode=cell) %>%
  dplyr::inner_join(select(def,file,barcode,sample),.,c("file","barcode")) %>%
  select(-file,-barcode) %>% dplyr::rename(ens_gene=gene)
Parsed with column specification:
cols(
  gene = col_character(),
  cell = col_character(),
  count = col_double()
)
Parsed with column specification:
cols(
  gene = col_character(),
  cell = col_character(),
  count = col_double()
)
`cols` is now required when using unnest().
Please use `cols = c(data)`
print(umi)

## sample, barcode, file を忘れずに!

mat <- umi %>% annotate %>%
  dplyr::mutate(chr=factor(chr,c(1:maxchrom,"X","Y","MT"))) %>%
  filter(!is.na(chr)) %>% spread(sample,count,fill=0)

## to check read vias, this add read number as "n" column (2019/4/19)
def <- umi %>% count(sample,wt=count) %>% dplyr::inner_join(def,.) %>% dplyr::rename(count=n)
Joining, by = "sample"
####-----------#### 




# Set reference levels according to the contrast
#for(x in keep(contrast,is.character))
#  def[[x[1]]] <- relevel(factor(def[[x[1]]]),x[3])

#umi <- def$file %>% unique %>% tibble(file=.) %>% 
#  mutate(data=map(file,readr::read_tsv,progress=FALSE)) %>%
#  unnest() %>% dplyr::rename(barcode=cell) %>%
#  inner_join(select(def,file,barcode,sample),.,c("file","barcode")) %>%
#  select(-file,-barcode) %>% dplyr::rename(ens_gene=gene)

#mat <- umi %>% annotate %>%
#  mutate(chr=factor(chr,c(1:maxchrom,"X","Y","MT"))) %>%
#  filter(!is.na(chr)) %>% spread(sample,count,fill=0)

print(mat)

## to check read vias, this add read number as "n" column (2019/4/19)
#def <- umi %>% count(sample,wt=count) %>% inner_join(def,.) %>% dplyr::rename(count=n)

print(def)


##====================================##
# 確認 (20191204) 2つの値は一緒か?
# 生のデータカウント中の遺伝子総数

umi %>% group_by(ens_gene) %>% summarise %>% nrow()
`summarise()` ungrouping output (override with `.groups` argument)
[1] 22606
umi %>% spread(sample,count,fill=0) %>% nrow()
[1] 22606
mat %>% nrow()
[1] 22460
mat %>% filter(chr!="MT") %>% nrow() # MTなし
[1] 22425
# matでは、chr等が不明なものは省いている。
# DEGでは、さらにMTも省いている。
##====================================##

Reads breakdown

Total reads

bychr <- mat %>% select(-(1:3)) %>%
  gather("sample","count",-chr) %>%
  group_by(chr,sample) %>% summarise(total=sum(count)) %>% ungroup
`summarise()` regrouping output by 'chr' (override with `.groups` argument)
ggplot(bychr,aes(reorder(sample,dplyr::desc(sample)),total/1e6,fill=chr)) +
  theme_linedraw() + geom_bar(stat="identity") + coord_flip() +
  xlab("sample") + ylab("million reads") + ggsci::scale_fill_igv() +
  scale_x_discrete(limits = rev(levels(sample)))

NA
NA

Biotype

bt <- mat %>% select(-c(1,2,4)) %>% group_by(biotype) %>%
  summarise_all(sum) %>% filter_at(-1,any_vars(. > 1000))
bt %>% tibble::column_to_rownames("biotype") %>%
  as.matrix %>% t %>% mosaicplot(las=2,shade=TRUE)

Correlations

drop rows with all 0 -> +1/2 -> geom.scale -> log -> Pearson’s

matf <- mat %>% filter(chr!="MT") %>% filter_at(-(1:4),any_vars(. > 0))
X <- matf %>% select(-(1:4)) %>% as.matrix
rownames(X) <- matf$ens_gene
lX <- log(gscale(X+0.5))
R <- cor(lX); diag(R) <- NA
pheatmap::pheatmap(R,color=viridis::viridis(256))

Dimension reduction

# set scale=TRUE if the patterns (not level) is the matter
p <- prcomp(t(lX[rank(-apply(lX,1,var)) <= ntop,]),scale=scalerows,center=TRUE)
screeplot(p,las=2,main="Importance")

print(summary(p)$imp[,seq(min(10,ncol(X)))])
                            PC1      PC2      PC3      PC4      PC5      PC6      PC7      PC8      PC9    PC10
Standard deviation     19.05148 5.867174 3.397302 3.035996 2.845318 2.570355 2.484155 2.407304 2.265719 2.23333
Proportion of Variance  0.72592 0.068850 0.023080 0.018430 0.016190 0.013210 0.012340 0.011590 0.010270 0.00998
Cumulative Proportion   0.72592 0.794760 0.817850 0.836280 0.852470 0.865690 0.878030 0.889620 0.899890 0.90986
label <- def %>% filter(sample %in% colnames(X))
df <- data.frame(p$x) %>% as_tibble(rownames="sample") %>%
  inner_join(label,.) %>% select(-file)
Joining, by = "sample"
print(df)
ggpoints(df,modifyList(aes(PC1,PC2),myaes))



#----- nuleosomeでuwotの調子が悪いので消す 190827 -----#

set.seed(seed)
um <- uwot::umap(p$x,n_nei,2)
df <- as_tibble(um) %>% rename(UMAP1=V1,UMAP2=V2) %>% bind_cols(df)
The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
ggpoints(df,modifyList(aes(UMAP1,UMAP2),myaes))


print(df)

##  kuwakado 変更 ##
#ggpoints <- function(x,...) 
#  ggplot(x,...) + geom_point(stroke=1) + theme_minimal() + mycolor

#------------------------------------------------------#

#ggpoints(df,modifyList(aes(PC1,PC2),myaes2))
#set.seed(seed)
#um <- uwot::umap(p$x,n_nei,2)
#df <- as_tibble(um) %>% rename(UMAP1=V1,UMAP2=V2) %>% bind_cols(df)
#ggpoints(df,modifyList(aes(UMAP1,UMAP2),myaes2))
## ## ## ##

DESeq2

Fit model

dds <- DESeq2::DESeqDataSetFromMatrix(X[,label$sample],label,model)
converting counts to integer mode
dds <- DESeq2::DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
-- note: fitType='parametric', but the dispersion trend was not well captured by the
   function: y = a/x + b, and a local regression fit was automatically substituted.
   specify fitType='local' or 'mean' to avoid this message next time.
final dispersion estimates
fitting model and testing
#=====#

dds <- DESeq2::estimateSizeFactors(dds)
norm <- DESeq2::counts(dds,normalized=TRUE) #DEGを取った後のクラスタリングに使う。

normalizedcount <- as.data.frame(norm) %>% tibble::rownames_to_column("ens_gene") %>% as_tibble
readr::write_csv(normalizedcount, "./BRB0438re_H3mm18KO_mouse_CTX_normalizedcount_fin200523_add200831.csv")

norm_gene <- normalizedcount %>% inner_join(e2g)
Joining, by = "ens_gene"
readr::write_csv(norm_gene, "./BRB0438re_H3mm18KO_mouse_CTX_normalizedcount_genename_fin200523_add200831.csv")
nrow(norm_gene)
[1] 22425
ncol(norm_gene)
[1] 29
####--- + size factors を書き出し ------------------####
as.data.frame(DESeq2::sizeFactors(dds))  %>% tibble::rownames_to_column("sample") %>% readr::write_csv("./BRB0438re_H3mm18KO_mouse_CTX_sizefactors_fin200523_add200831.csv")



#count_dds <- estimateSizeFactors(dds)
#counts(count_dds, normalized=TRUE)

vst => z score


vsd <- DESeq2::vst(dds) #normalized countが入っている。(vstかrlog)
#Xd <- summarisedExperiment::assay(vsd) # 全て選択(200326) 20190920を元に (191024)
Xd <- SummarizedExperiment::assay(vsd) # 全て選択(200326) 20190920を元に (191024)
Xs <- Xd %>% t %>% scale %>% t

zscore <- Xs %>% as.data.frame() %>% tibble::rownames_to_column("ens_gene") %>% as_tibble
zscore_type <- zscore  %>% annotate %>% dplyr::select("ens_gene","ext_gene", "biotype","chr", all_of(sort_mouse))



readr::write_csv(zscore, "BRB0438re_H3mm18KO_mouse_CTX_zscore_all_fin200523_add200831.csv")
readr::write_csv(zscore_type, "BRB0438re_H3mm18KO_mouse_CTX_zscore_type_all_fin200523_add200831.csv")

nrow(zscore_type)
[1] 22425

Diagnostics plot

DESeq2::sizeFactors(dds) %>%
  {tibble(sample=names(.),sizeFactor=.)} %>%
  ggplot(aes(sample,sizeFactor)) + theme_minimal() +
  geom_bar(stat="identity") + coord_flip()

DESeq2::plotDispEsts(dds)

Extract results

res <- mapply(function(x)
  DESeq2::results(dds,x,lfcThreshold=lfcthreth,alpha=fdr)
,contrast)

print(fdr)
[1] 0.2
#re <- map(res,as_tibble,rownames="ens_gene") %>%
#  tibble(aspect=factor(names(.),names(.)),data=.) %>%
#  mutate(data=map(data,annotate)) %>%
#  unnest(cols = "data") %>% filter(padj<fdr) #191120修正 unnest() 

re_all <- map(res,as_tibble,rownames="ens_gene") %>%
  tibble(aspect=factor(names(.),names(.)),data=.) %>%
  mutate(data=map(data,annotate)) %>%
  unnest(cols = "data")



re <- re_all %>% filter(padj<fdr) #191120修正 unnest() 

nrow(re_all %>% filter(aspect=="group1_CTX_Day5_H3mm18KO_vs_WT"))
[1] 22425
nrow(re %>% filter(aspect=="group1_CTX_Day5_H3mm18KO_vs_WT"))
[1] 250
fc <- re %>% select(1:7) %>% filter(aspect!="Intercept") %>% spread(aspect,log2FoldChange,fill=0) # 20200803 修正

imap(res,~{
  cat(paste0("-- ",.y," --"))
  DESeq2::summary(.x) #191120修正 DESeq2::summary.DESeqResults(.x)
}) %>% invisible
-- Intercept --
out of 22425 with nonzero total read count
adjusted p-value < 0.2
LFC > 0 (up)       : 10766, 48%
LFC < 0 (down)     : 336, 1.5%
outliers [1]       : 6, 0.027%
low counts [2]     : 6957, 31%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group1_SKM_Day0_H3mm18KO_vs_WT --
out of 22425 with nonzero total read count
adjusted p-value < 0.2
LFC > 0 (up)       : 0, 0%
LFC < 0 (down)     : 0, 0%
outliers [1]       : 6, 0.027%
low counts [2]     : 0, 0%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group1_CTX_Day5_H3mm18KO_vs_WT --
out of 22425 with nonzero total read count
adjusted p-value < 0.2
LFC > 0 (up)       : 33, 0.15%
LFC < 0 (down)     : 217, 0.97%
outliers [1]       : 6, 0.027%
low counts [2]     : 20865, 93%
(mean count < 61)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group1_CTX_Day14_H3mm18KO_vs_WT --
out of 22425 with nonzero total read count
adjusted p-value < 0.2
LFC > 0 (up)       : 0, 0%
LFC < 0 (down)     : 0, 0%
outliers [1]       : 6, 0.027%
low counts [2]     : 0, 0%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

GSEA

msig <- msigdbr::msigdbr(species)
fgsea_msig <- partial(fgsea::fgsea,with(msig,split(gene_symbol,gs_name)))
gscat <- msig %>% select(gs_name,gs_cat,gs_subcat) %>%
  distinct() %>% rename(pathway=gs_name)

#gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
#  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
#  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
#  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
#  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=","))

# gsea 修正ver [20190621]
#gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
#  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
#  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
#  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
#  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=",")) %>%
#  group_by(aspect,gs_cat,gs_subcat) %>%
#  mutate(padj=p.adjust(pval,"BH")) %>% ungroup()

# gsea 修正ver [20190627]
gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
  filter(map(l2fc,length)>10) %>%
  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=",")) %>%
  group_by(aspect,gs_cat,gs_subcat) %>%
  mutate(padj=p.adjust(pval,"BH")) %>% ungroup()
`summarise()` ungrouping output (override with `.groups` argument)
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
 警告メッセージ: 
 base::options(global_options) で:  警告メッセージ: 

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で:  警告メッセージ: 

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で:  警告メッセージ: 

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
Joining, by = "pathway"
hallmark <- gsea %>% filter(gs_cat=="H") %>%
  mutate(pathway=sub("^HALLMARK_","",pathway)) %>% 
  group_by(aspect) %>% nest %>%
  mutate(plt=map2(data,aspect,~
    ggplot(.x,aes(reorder(pathway,NES),NES,fill=padj<0.1)) +
    ggtitle(.y) + xlab("Hallmark gene sets") +
    geom_bar(stat="identity") + theme_minimal() + coord_flip() +
    theme(legend.position = "none") + ggsci::scale_fill_aaas())
  )
print(hallmark$plt)
[[1]]

See MSigDB Collections: http://software.broadinstitute.org/gsea/msigdb/collections.jsp

Write-out tables

if(exists("fc"))   readr::write_csv(fc,"./2gun/BRB0438re_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_l2fc_fdr0p2ver_fin200523_add200831.csv")
if(exists("re"))   readr::write_csv(re,"./2gun/BRB0438re_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_results_fdr0p2ver_fin200523_add200831.csv")
if(exists("re_all"))   readr::write_csv(re_all,"./2gun/BRB0438re_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_resultsall_fdr0p2ver_fin200523_add200831.csv")
if(exists("gsea")) readr::write_csv(gsea,"./2gun/BRB0438re_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_gsea_fdr0p2ver_fin200523_add200831.csv")

Write-out tables Hallmark


hallmark_gsea <- gsea %>% filter(gs_cat=="H") %>% mutate(pathway=sub("^HALLMARK_","",pathway)) %>% group_by(aspect) %>% filter(aspect=="group1_CTX_Day5_H3mm18KO_vs_WT") 

if(exists("hallmark_gsea"))   readr::write_csv(hallmark_gsea,"./2gun/BRB0438re_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_hallmark_gsea_CTX_Day5_H3mm18KO_vs_WT_fdr0p2ver_fin200523_add200831.csv")

MAplot

# SKM
maplot <- DESeq2::plotMA(res$group1_SKM_Day0_H3mm18KO_vs_WT , ylim=c(-4,4), main="SKM Day0 H3mm18KO vs WT")
print(maplot)

# CTX
maplot <- DESeq2::plotMA(res$group1_CTX_Day5_H3mm18KO_vs_WT, ylim=c(-4,4), main="CTX Day5 H3mm18KO vs WT")
print(maplot)
maplot <- DESeq2::plotMA(res$group1_CTX_Day14_H3mm18KO_vs_WT, ylim=c(-4,4), main="CTX Day14 H3mm18KO vs WT")
print(maplot)

# intact
#maplot <- DESeq2::plotMA(res$group1_intact_Day5_H3mm18KO_vs_WT , ylim=c(-4,4), main="intact Day5 H3mm18KO vs WT")
#print(maplot)
#maplot <- DESeq2::plotMA(res$group1_intact_Day14_H3mm18KO_vs_WT, ylim=c(-4,4), main="intact Day14 H3mm18KO vs WT")
#print(maplot)

#coef(dds)

coef_dds <- coef(dds) %>% as.data.frame() %>% tibble::rownames_to_column("ens_gene") %>% as_tibble

readr::write_csv(coef_dds, "BRB0438re_H3mm18KO_mouse_CTX_coef_fin200523_add200831.csv")

Set_cutoff <- 10.0

## 各時刻の平均を計算し、normalized count > 10 を超えるものを抽出する。

#----- SKMとCTXのみ取り出す ---# 20191205
norm_plotlist_all <- normalizedcount %>% gather("sample", "normalized",-(ens_gene)) %>% inner_join(def, by = "sample")
norm_plotlist_all <- norm_plotlist_all %>% filter(intact_CTX=="CTX"|intact_CTX=="SKM") %>% mutate(WT_KO=factor(WT_KO, c("H3mm18KO","WT"))) %>% mutate(Day=factor(Day, c("Day0","Day5","Day14"))) %>% mutate(intact_CTX=factor(intact_CTX, c("CTX","SKM")))

#notm_plotlist_cutoff <- norm_plotlist_all %>% annotate() %>% group_by(ens_gene, ext_gene, Day, intact_CTX) %>% summarise(groupMean=mean(normalized))  %>% ungroup() %>% dplyr::select(ens_gene, ext_gene) %>% unique()


notm_plotlist_beforecutoff <- norm_plotlist_all %>% annotate() %>% group_by(ens_gene, ext_gene, Day, intact_CTX) %>% summarise(groupMean=mean(normalized))
`summarise()` regrouping output by 'ens_gene', 'ext_gene', 'Day' (override with `.groups` argument)
notm_plotlist_cutoff <- notm_plotlist_beforecutoff %>% filter(groupMean > Set_cutoff) %>% ungroup() %>% dplyr::select(ens_gene, ext_gene) %>% unique()

nrow(notm_plotlist_beforecutoff %>% ungroup() %>% dplyr::select(ens_gene, ext_gene) %>% unique()) #この値をMAplotのx軸に使用
[1] 22425
nrow(notm_plotlist_cutoff) #解析対象を絞る (後の全体のクラスタリングに使用)
[1] 7900

norm_plotlist_all %>% readr::write_csv("Norm_deftable.csv")
notm_plotlist_beforecutoff %>% readr::write_csv("Norm_groupMean.csv")
notm_plotlist_cutoff  %>% readr::write_csv("Norm_groupMean_cutoff10.csv")


nrow(notm_plotlist_beforecutoff)
[1] 67275
nrow(notm_plotlist_cutoff)
[1] 7900

MAplot (by hand)

ASCs_list from “Histone H3.3 sub-variant H3mm7 is required for normal skeletal muscle regeneration”, Harada, Maehara et al.

### ---------------------- ###

#MGIGO <- readr::read_tsv("/home/guestA/o70578a/akuwakado/kuwakado/Reference_files/Mouse_Genome_Informatics_mgi_GO/MGI_Annotations_20200806download/GO_term_summary_20200805_220700__GO0035914_skeletal_muscle_cell_differentiation.txt",col_names = c("MGI","ext_gene"))

#MGISC_tableGO <- readr::read_tsv("/home/guestA/o70578a/akuwakado/kuwakado/BRBSeq/H3mm18KO_and_H3p3KO_0438/R_server__mouse_H3mm18KO_CTX__190924-/Final_Last_Rserver_200523_add200831/table_GOterm_SCs.txt",col_names = c("file"))


#MGISC <- MGISC_tableGO$file %>% unique %>% tibble(file=.) %>% 
#  dplyr::mutate(data=map(file,readr::read_tsv,progress=FALSE)) %>%
#  unnest(cols = c(data))

#MGISC_gene <- MGISC %>% dplyr::select(Symbol,`Annotated Term`) %>% group_by(Symbol) %>% summarise(count=n(),  `Annotated Term`=paste(`Annotated Term`,collapse = ", ")) %>% unique()   %>% mutate(list1=case_when(str_detect(`Annotated Term`, "negative")~"negative",str_detect(`Annotated Term`, "positive")~"positive",str_detect(`Annotated Term`, "satellite cell activation")~"positive",TRUE ~ "Other")) %>% rename(ext_gene=Symbol)

#%>% filter(list1=="positive")


SKMH3mm7 <- readr::read_tsv("/home/guestA/n70275b/work/tissuechil/tisuues/skmuscle_markers.txt") # 43個
Parsed with column specification:
cols(
  gene_id = col_character(),
  gene = col_character()
)
#SCs_suplist <- c("Acvr2a","Cav1","Cd34","Cdh15","Cxcl12","Cxcr4","Des","Egfr","Foxk1","Hoxc10","Itga4","Itga7","Itgb1","Lbx1","Met","Myod1","Ncam1","Ngfr","Pax7","Sdc3","Sdc4","Sox9","Vcam1","Me1","Vps72","Tceal5","Hnrnpa2b1","0610012G03Rik","Sgk1","Hdac5","Zcrb1","Gpc1","Cbfb","Gpx1","Wdr26","Mff","Cd63","Col1a1","Tspan9","Atp5b","Tnnc2","Ndufc2","Nfib","Hbb-bs","Sf1","Tns1","Hrc","Smox","Ech1","Actc1","Krtcap2","Sbk2") # 52個
# かぶりは23個


############
## Fig1より
AQSC_list <- c("Cxcl12","Cav1","Egfr","Cd34","Vcam1","Megf10","Msx1","S1pr1","Ncam1","Sox9")
#e2g %>% filter(ext_gene %in% AQSC_list)
ASC_list <- c("Sdc3","Cxcr4","Nes","Ndn","Myf5","Itgb1","Adgrg3","Myod1","Sox8","Erbb2","Nrn1") #"Sdc3","Cxcr4","Nes","Ndn","Myf5",
#e2g %>% filter(ext_gene %in% ASC_list)
QSC_list <- c("Pax7","Sdc4","Bdnf","Ngfr","Calcr","Cdh15","Pax3","Cadm1") #ADD "Bdnf","Calcr","Pax3","Cadm1" OK plus 2
#e2g %>% filter(ext_gene %in% QSC_list)
MF_list <- c("Acvr2a","Des","Foxk1","Hoxc10","Itga4","Itga7","Lbx1","Met","Erbb3","Erbb4","Mstn") #ADD "Erbb4""Erbb3""Mstn" OK plus 8
#e2g %>% filter(ext_gene %in% MF_list)
############

markerSCs <- e2g %>% filter(ens_gene %in% SKMH3mm7$gene_id)  %>% mutate(clus=case_when(ext_gene %in% AQSC_list ~"ASC",ext_gene %in% ASC_list ~"ASC",ext_gene %in% QSC_list ~"QSC",ext_gene %in% MF_list ~"MF",TRUE ~ "other")) %>% mutate(List=factor(clus, c("ASC","QSC","MF","other"))) %>% filter(clus %in% c("ASC","QSC","MF"))

#markerSCs <- e2g %>% filter(ens_gene %in% SKMH3mm7$gene_id)  %>% mutate(clus=case_when(ext_gene %in% AQSC_list ~"ASC_QSC",ext_gene %in% QSC_list ~"QSC",ext_gene %in% ASC_list ~"ASC",ext_gene %in% MF_list ~"MF",TRUE ~ "other")) %>% mutate(List=factor(clus, c("ASC","QSC","ASC_QSC","MF","other"))) %>% filter(clus %in% c("ASC","QSC","ASC_QSC"))

#%>% mutate(clus=case_when(List %in% c("ASC","QSC","ASC_QSC") ~"SC",List %in% c("MF") ~"MF",List %in% c("SKM") ~"SKM",TRUE ~ ""))

markerSCs %>% group_by(clus) %>% summarise(count=n(),  gene=paste(ext_gene,collapse = ", "))
`summarise()` ungrouping output (override with `.groups` argument)
markerSCs %>% readr::write_csv("./SCsmakerlist_inMAplot.csv")

#marker_MA <- markerSCs %>% filter(List %in% c("ASC","QSC","ASC_QSC"))
#marker_MA <- e2g %>% filter(ext_gene %in% MGIGO$ext_gene)
#marker_MA <- e2g %>% filter(ext_gene %in% c("Capn3","Sox15"))
#marker_MA <- e2g %>% filter(ext_gene %in% SCs_suplist)


#marker_MA <- e2g %>% filter(ext_gene %in% MGISC_gene$ext_gene) %>% left_join(MGISC_gene)
marker_MA <- e2g %>% filter(ext_gene %in% markerSCs$ext_gene) %>% left_join(markerSCs)
Joining, by = c("ens_gene", "ext_gene", "biotype", "chr")

#f_SCs <- function(x) x %>% filter(ext_gene %in% SCs_list) #作図用
#fc %>% f_SCs

#f_MF <- function(x) x %>% filter(ext_gene %in% MF_list) #作図用
#fc %>% f_MF

#re_all_plot <- re_all %>% mutate(cluster=case_when(ext_gene %in% SCs_list~"SC",ext_gene %in% MF_list~"MF",TRUE ~ "FALSE")) %>% mutate(label_text=case_when(ext_gene %in% ASCs_list ~ ext_gene,TRUE ~ ""))  %>% mutate(cluster=factor(cluster, c("SC","MF","FALSE")))

#f_markerMA_in <- function(x) x %>% filter(ens_gene %in% marker_MA$ens_gene)

#f_markerMA_in <- function(x) x %>% filter(ens_gene %in% marker_MA$ens_gene) %>% left_join(marker_MA)
#f_markerMA_in_ASCs <- function(x) x %>% filter(ens_gene %in% marker_MA$ens_gene) %>% left_join(marker_MA) %>% filter(cluster %in% c("ASC"))
#f_markerMA_out <- function(x) x %>% filter(!ens_gene %in% marker_MA$ens_gene)


f_markerMA_in <- function(x) x %>% filter(ens_gene %in% marker_MA$ens_gene)
f_markerMA_in_ASCs <- function(x) x %>% filter(ens_gene %in% marker_MA$ens_gene) %>% left_join(marker_MA) %>% filter(cluster %in% c("ASC"))
f_markerMA_out <- function(x) x %>% filter(!ens_gene %in% marker_MA$ens_gene)

#re_all_plot <- re_all %>% mutate(cluster=case_when(ens_gene %in% marker_MA$ens_gene~"marker",TRUE ~ "FALSE")) %>% mutate(label_text=case_when(ext_gene %in% marker_MA$ext_gene ~ ext_gene,TRUE ~ ""))%>% mutate(cluster=factor(cluster, c("marker","FALSE")))


#re_all_plot <- re_all %>% left_join(marker_MA) %>% mutate(cluster=case_when(!is.na(list1)~list1,TRUE ~ "FALSE")) %>% mutate(label_text=case_when(ext_gene %in% marker_MA$ext_gene ~ ext_gene,TRUE ~ "")) %>%  mutate(cluster=factor(cluster, c("positive","Other","negative")))

re_all_plot <- re_all %>% left_join(marker_MA) %>% mutate(cluster=case_when(!is.na(clus)~clus,TRUE ~ "FALSE"))  %>% mutate(label_text=case_when(ext_gene %in% AQSC_list ~ ext_gene, ext_gene %in% ASC_list ~ ext_gene,ext_gene %in% QSC_list ~ext_gene, TRUE ~ ""))  %>% mutate(cluster=factor(cluster, c("ASC","QSC","MF","FALSE")))
Joining, by = c("ens_gene", "ext_gene", "biotype", "chr")
#%>%  mutate(cluster=factor(cluster, c("SC","MF","SKM")))



####
re_select_plot <- re_all_plot %>% filter(aspect!="Intercept") %>% mutate(Day=case_when(aspect=="group1_SKM_Day0_H3mm18KO_vs_WT"~"Day0",aspect=="group1_CTX_Day5_H3mm18KO_vs_WT"~"Day5",aspect=="group1_CTX_Day14_H3mm18KO_vs_WT"~"Day14",TRUE ~ "FALSE"))  %>% left_join(notm_plotlist_beforecutoff)  %>% mutate(Day=factor(Day, c("Day0","Day5","Day14"))) 
Joining, by = c("ens_gene", "ext_gene", "Day")
Daymean <- re_select_plot %>% group_by(Day) %>% summarise(DayMean=mean(groupMean))
`summarise()` ungrouping output (override with `.groups` argument)
Mean_color <- "#B8860B"

Daymean

Allgene_num <- re_select_plot %>% dplyr::select(ens_gene) %>% unique() %>% nrow()
marker_num <- re_select_plot %>% f_markerMA_in %>% dplyr::select(ens_gene) %>% unique() %>% nrow()
marker_num_sum <- re_select_plot %>% f_markerMA_in %>% dplyr::select(ens_gene,ext_gene,cluster) %>% unique() %>% group_by(cluster) %>% summarise(count=n())
`summarise()` ungrouping output (override with `.groups` argument)
gggglabel <- paste(Allgene_num, "genes,", marker_num,"marker genes (",marker_num_sum$cluster[1],marker_num_sum$count[1],marker_num_sum$cluster[2],marker_num_sum$count[2],marker_num_sum$cluster[3],marker_num_sum$count[3],")",sep=" ")



re_select_plot %>% f_markerMA_in %>% dplyr::select(ens_gene,ext_gene,cluster) %>% unique() %>% arrange(cluster)
re_select_plot %>% f_markerMA_in %>% dplyr::select(ens_gene,ext_gene,cluster) %>% unique() %>% arrange(cluster) %>% readr::write_csv("./Dayall_MAplot_SKMlist.csv")

re_select_plot %>% readr::write_csv("./Dayall_MAplotdata.csv")

########

ggmaplot <- re_select_plot  %>%  ggplot(aes(groupMean,log2FoldChange,color=cluster))+geom_point(size=0.1, alpha = 0.5,data=f_markerMA_out,color="#bdbdbd") + geom_abline(intercept=0,slope=0,colour="black",size=0.2)  +geom_point(aes(groupMean,log2FoldChange,color=cluster),size=0.3, data=f_markerMA_in) + scale_x_log10() + theme_bw() + theme(legend.position = "top") + ggtitle(gggglabel) + ylim(-5.0, 5.0) + scale_color_manual(values = c("#ff0000","#0000ff","#000000")) + facet_wrap(~Day,ncol=1) + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8))


#,panel.grid=element_blank()

ggsave(file="DayAll_MAplot.pdf", plot = ggmaplot, width = 7, height = 8, dpi = 120)
plot(ggmaplot)


########


ggmaplot <- re_select_plot  %>%  ggplot(aes(groupMean,log2FoldChange,color=cluster))+geom_point(size=0.1, alpha = 0.5,data=f_markerMA_out,color="#bdbdbd") + geom_abline(intercept=0,slope=0,colour="black",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") +geom_point(aes(groupMean,log2FoldChange,color=cluster),size=0.3, data=f_markerMA_in) + scale_x_log10() + theme_bw() + theme(legend.position = "top") + ggtitle(gggglabel) + ylim(-5.0, 5.0) + scale_color_manual(values = c("#ff0000","#0000ff","#000000")) + facet_wrap(~Day,ncol=1) + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8))

ggsave(file="DayAll_MAplot_Mean.pdf", plot = ggmaplot, width = 7, height = 8, dpi = 120)
plot(ggmaplot)

NA
NA

density_color_low <- "#FFFFFF"
density_color_high <- "blue"
density_color_high <- "#FFD400"



#density_color_high <- "gray"

#DAA520

#Mean_groupmean <- mean(re_select_plot$groupMean)
#Mean_log2FC <- mean(re_select_plot$log2FoldChange)

ffff <- re_select_plot  %>% mutate(Day=factor(Day, c("Day0","Day5","Day14")))  %>%  ggplot(aes(x=groupMean,y=log2FoldChange))  + stat_density2d(aes(fill=..density..), geom = "raster",contour = FALSE)+ scale_fill_gradient(low = density_color_low, high = density_color_high) + scale_x_log10(breaks=10^(-1:4),limits= c(0.1, 10000))  + geom_abline(intercept=0,slope=0,colour="#000000",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") + geom_density2d(color="#ff0000",data=f_markerMA_in_ASCs,size=0.1, bins=7) +geom_point(aes(groupMean,log2FoldChange,color=cluster),size=1.0, data=f_markerMA_in_ASCs) + ylim(-1,1) + facet_wrap(~Day, ncol = 1) + theme_bw() + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8),panel.grid=element_blank())  + scale_color_manual(values = c("#ff0000","#0000ff","#000000"))


ffff

ggsave(file="DayAll_densityMAplot_ASC.pdf", plot = ffff, width = 4, height = 8, dpi = 120)

ffff <- re_select_plot  %>% mutate(Day=factor(Day, c("Day0","Day5","Day14")))  %>%  ggplot(aes(x=groupMean,y=log2FoldChange))  + stat_density2d(aes(fill=..density..), geom = "raster",contour = FALSE)+ scale_fill_gradient(low = density_color_low, high = density_color_high) + scale_x_log10(breaks=10^(-1:4),limits= c(0.1, 10000))  + geom_abline(intercept=0,slope=0,colour="#000000",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") + geom_density2d(color="#ff0000",data=f_markerMA_in_ASCs,size=0.1, bins=7) +geom_point(aes(groupMean,log2FoldChange,color=cluster),size=1.0, data=f_markerMA_in) + ylim(-1,1) + facet_wrap(~Day, ncol = 1) + theme_bw() + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8),panel.grid=element_blank())  + scale_color_manual(values = c("#ff0000","#0000ff","#000000"))

ffff

ggsave(file="DayAll_densityMAplot_SCs.pdf", plot = ffff, width = 4, height = 8, dpi = 120)

ffff <- re_select_plot %>% mutate(Day=factor(Day, c("Day0","Day5","Day14")))  %>%  ggplot(aes(x=groupMean,y=log2FoldChange)) + scale_fill_gradient(low = density_color_low, high = density_color_high) + scale_color_gradient(low = "#000000", high = "#ff0000") + stat_density2d(aes(fill=..density..), geom = "raster",contour = FALSE) + geom_density2d(aes(color=..level..),data=f_markerMA_in_ASCs,size=0.1, bins=7) + scale_x_log10(breaks=10^(-1:4),limits= c(0.1, 10000))  + geom_abline(intercept=0,slope=0,colour="#000000",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") + ylim(-1,1) + facet_wrap(~Day, ncol = 1) + theme_bw() + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8),panel.grid=element_blank())  +geom_point(aes(groupMean,log2FoldChange),size=1.0, data=f_markerMA_in_ASCs)

ffff
ggsave(file="DayAll_densityMAplot_ASCplotvsAll.pdf", plot = ffff, width = 4, height = 8, dpi = 120)

NA
NA




ffff <- re_select_plot  %>% mutate(Day=factor(Day, c("Day0","Day5","Day14")))  %>%  ggplot(aes(x=groupMean,y=log2FoldChange))  + stat_density2d(aes(fill=..density..), geom = "raster",contour = FALSE)+ scale_fill_gradient(low = density_color_low, high = density_color_high) + scale_x_log10()  + geom_abline(intercept=0,slope=0,colour="#000000",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") + geom_density2d(color="#ff0000",data=f_markerMA_in_ASCs,size=0.1, bins=7) +geom_point(aes(groupMean,log2FoldChange,color=cluster),size=1.0, data=f_markerMA_in) + ylim(-1,1) + facet_wrap(~Day, ncol = 1) + theme_bw() + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8),panel.grid=element_blank())  + scale_color_manual(values = c("#ff0000","#0000ff","#000000")) + geom_text_repel(aes(label = label_text), segment.color = "#000000", segment.size = 0.1) 


ffff

ggsave(file="DayAll_densityMAplot_SCs_title.pdf", plot = ffff, width = 6, height = 12, dpi = 120)

mkde2d <- MASS::kde2d(re_select_plot\(groupMean,re_select_plot\)log2FoldChange,lims = c(c(0.1, 10000), range(-1,1)))


notm_plotlist_cutoff 10.0 を クラスタリング

191204作成 以前のものを修正して作成

4つのクラスターに分ける (with Day0, Day5, Day14, SKM & CTXのみ, kmeans)

Clustering (all genes)

clustering H3.3

#20191205修正と作成

def_list_select <- def %>% filter(sample %in% sort_mouse)

cluster_number <- 4

csvfilepath <- "BRB0438re_noumi_190515-H3mm18KO_CTX"


##--------- clustering -----------#
set.seed(3)

# H3.3で
 
zscore_BRB_s <- zscore_type %>% dplyr::select("ens_gene",all_of(def_list_select$sample))  %>% filter(across(where(is_double), ~ (.x != 0)|(.x == 0))) %>% filter(ens_gene %in% notm_plotlist_cutoff$ens_gene)
#zscore_BRB_s <- zscore_H3p3 %>% filter(across(where(is_double), ~ (.x != 0)|(.x == 0)))

nrow(zscore_type)
[1] 22425
nrow(zscore_BRB_s)
[1] 7900
Xs_clus <- zscore_BRB_s %>% dplyr::select(-ens_gene) %>% as.matrix()
rownames(Xs_clus) <- zscore_BRB_s$ens_gene

km_allcutoff <- kmeans(Xs_clus,cluster_number,nstart = 25,algorithm = "Lloyd")
 10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした 
kmc_allcutoff <- km_allcutoff$centers %>% as_tibble(rownames="cluster") %>% gather(sample,val,-cluster) %>% inner_join(def_list_select)
Joining, by = "sample"
kmc_allcutoff_group <- kmc_allcutoff

#kmc_LRT_group <- kmc_LRT %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))

#kmc_LRT_group <- kmc_LRT_group %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#kmc_LRT_group <- kmc_LRT_group %>% mutate(time=factor(time, c("UI","0h","24h","48h")))

#gggglabel <- paste("k-means: Total",nrow(Xs_H3p3),"[1]",km_allcutoff$size[1],"[2]",km_allcutoff$size[2],"[3]",km_allcutoff$size[3],"[4]",km_allcutoff$size[4],"[5]",km_allcutoff$size[5],"[6]",km_allcutoff$size[6],sep=" ")

gggglabel <- paste("Original",nrow(zscore_type),"k-means: Total",nrow(zscore_BRB_s),"[1]",km_allcutoff$size[1],"[2]",km_allcutoff$size[2],"[3]",km_allcutoff$size[3],"[4]",km_allcutoff$size[4],sep=" ")


#gggglabel <- paste("Original",nrow(zscore_type),"k-means: Total",nrow(zscore_BRB_s),"[1]",km_allcutoff$size[1],"[2]",km_allcutoff$size[2],"[3]",km_allcutoff$size[3],"[4]",km_allcutoff$size[4],"[5]",km_allcutoff$size[5],"[6]",km_allcutoff$size[6],sep=" ")

#------- size -------#

print(km_allcutoff$size) 
[1] 1529 2943 2393 1035
rrres_allcutoff <- km_allcutoff$cluster %>% tibble(ens_gene=names(.),cluster=.) %>% left_join(.,zscore_type) %>% arrange(cluster) %>% dplyr::select(ens_gene,ext_gene,biotype,chr,cluster,all_of(def_list_select$sample))
Joining, by = "ens_gene"
file_path <- paste("./Clustering_cutoff/", csvfilepath, "_kmeans_cluster.csv",sep="") 
readr::write_csv(rrres_allcutoff,file_path)

##------- PCA -------#

pcacluster_save <- prcomp(Xs_clus)$x %>% as_tibble %>% dplyr::select(PC1,PC2) %>% mutate(cluster=km_allcutoff$cluster) %>% ggplot(aes(PC1,PC2,colour=factor(cluster)))+geom_point(size=1.5,alpha=0.6)+coord_fixed()+theme_linedraw()+ggsci::scale_color_d3("category20")

file_path <- paste("./Clustering_cutoff/", csvfilepath, "_kmeans__pcacluster_PC1PC2.pdf",sep="") 
ggsave(plot=pcacluster_save,file=file_path, width = 10, height = 6, dpi = 120)
print(pcacluster_save)


pcacluster_save <- prcomp(Xs_clus)$x %>% as_tibble %>% dplyr::select(PC1,PC3) %>% mutate(cluster=km_allcutoff$cluster) %>% ggplot(aes(PC1,PC3,colour=factor(cluster)))+geom_point(size=1.5,alpha=0.6)+coord_fixed()+theme_linedraw()+ggsci::scale_color_d3("category20")

file_path <- paste("./Clustering_cutoff/", csvfilepath, "_kmeans__pcacluster_PC1PC3.pdf",sep="") 
ggsave(plot=pcacluster_save,file=file_path, width = 10, height = 6, dpi = 120)
print(pcacluster_save)



#================================================#


#================================================#
# CTXとSKMの色を分けてプロット (20191204 ver)
kmc_allcutoff_group_newgroup <- kmc_allcutoff_group %>% mutate(WT_KO=factor(WT_KO, c("H3mm18KO","WT"))) %>% mutate(Day=factor(Day, c("Day0","Day5","Day14"))) %>% mutate(intact_CTX=factor(intact_CTX, c("CTX","SKM")))
kmc_allcutoff_group_newgroup <- kmc_allcutoff_group_newgroup %>% mutate(group_new=paste(WT_KO,intact_CTX,Day,sep="_")) %>% mutate(type_new=paste(WT_KO,intact_CTX,sep="_"))
kmc_allcutoff_group_newgroup <- kmc_allcutoff_group_newgroup %>% mutate(type_new=factor(type_new, c("WT_CTX","H3mm18KO_CTX","WT_SKM","H3mm18KO_SKM")))

#------------------#
f_cluster <- function(x) x %>% group_by(group_new,type_new,Day,cluster) %>% summarise(avg=mean(val),se=sd(val)/sqrt(length(val))) %>% ungroup()
print(kmc_allcutoff_group_newgroup %>% group_by(group_new,type_new,Day) %>% summarise())
`summarise()` regrouping output by 'group_new', 'type_new' (override with `.groups` argument)
#-------#

#================================================#

#================================================#
# SKM(day0)もCTXと同じ色でプロット (20191204 ver)

#------------------#
f_cluster2 <- function(x) x %>% group_by(group_new, WT_KO, Day, cluster) %>% summarise(avg=mean(val),se=sd(val)/sqrt(length(val))) %>% ungroup()
print(kmc_allcutoff_group_newgroup %>% group_by(group_new, WT_KO, Day) %>% summarise())
`summarise()` regrouping output by 'group_new', 'WT_KO' (override with `.groups` argument)
#-------#

#================================================#

#===============================#
## SKM と CTX の色を分けて表示
# strip.text.x = element_text(size=24,face="italic")

cluster_save <- kmc_allcutoff_group_newgroup %>% ggplot(aes(Day,val,group=type_new,colour=type_new))+geom_line(size=1,aes(x=Day,y=avg,colour=type_new),data=f_cluster)+geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)

ggsave(plot=cluster_save,file="./Clustering_cutoff/BRB0438re_DEG_day5_2gunfdr0p2_ctxskm_kmeans4__cluster_type1__final_fin200523.pdf", width = 12, height = 4.5,  dpi = 120)
print(cluster_save)

#------------------#

cluster_save <- kmc_allcutoff_group_newgroup %>% ggplot(aes(Day,val,group=type_new,colour=type_new)) + geom_abline(intercept=0,slope=0,linetype="dashed",colour="gray") + geom_line(size=1,aes(x=Day,y=avg,colour=type_new),data=f_cluster)+geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)

ggsave(plot=cluster_save,file="./Clustering_cutoff/BRB0438re_DEG_day5_2gunfdr0p2_ctxskm_kmeans4__cluster_type1__final_dash_fin200523.pdf", width = 12, height = 4.5, dpi = 120)
print(cluster_save)

#------------------#

#===============================#
## SKMもCTXと同じ色で表示
# strip.text.x = element_text(size=24,face="italic")

cluster_save <- kmc_allcutoff_group_newgroup %>% ggplot(aes(Day,val,group=WT_KO,colour=WT_KO))+geom_line(size=1,aes(x=Day,y=avg,colour=WT_KO),data=f_cluster2)+geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)

ggsave(plot=cluster_save,file="./Clustering_cutoff/BRB0438re_DEG_day5_2gunfdr0p2_ctxskm_kmeans4__cluster_type2__final_fin200523.pdf", width = 12, height = 4.5,  dpi = 120)
print(cluster_save)

#------------------#

cluster_save <- kmc_allcutoff_group_newgroup %>% ggplot(aes(Day,val,group=WT_KO,colour=WT_KO)) + geom_abline(intercept=0,slope=0,linetype="dashed",colour="gray") +geom_line(size=1,aes(x=Day,y=avg,colour=WT_KO),data=f_cluster2)+geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)

ggsave(plot=cluster_save,file="./Clustering_cutoff/BRB0438re_DEG_day5_2gunfdr0p2_ctxskm_kmeans4__cluster_type2__final_dash_fin200523.pdf", width = 12, height = 4.5,  dpi = 120)
print(cluster_save)

#------------------#
z_cutoffclus1 <- rrres_allcutoff %>% filter(cluster=="1") %>% dplyr::rename(cutoffclus=cluster)
z_cutoffclus2 <- rrres_allcutoff %>% filter(cluster=="2") %>% dplyr::rename(cutoffclus=cluster)
z_cutoffclus3 <- rrres_allcutoff %>% filter(cluster=="3") %>% dplyr::rename(cutoffclus=cluster)
z_cutoffclus4 <- rrres_allcutoff %>% filter(cluster=="4") %>% dplyr::rename(cutoffclus=cluster)
#z_cutoffclus5 <- rrres_allcutoff %>% filter(cluster=="5") %>% dplyr::rename(cutoffclus=cluster)
#z_cutoffclus6 <- rrres_allcutoff %>% filter(cluster=="6") %>% dplyr::rename(cutoffclus=cluster)

nrow(rrres_allcutoff)
[1] 7900
nrow(z_cutoffclus1)
[1] 1529
nrow(z_cutoffclus2)
[1] 2943
nrow(z_cutoffclus3)
[1] 2393
nrow(z_cutoffclus4)
[1] 1035
#nrow(z_cutoffclus5)
#nrow(z_cutoffclus6)
nrow(rrres_allcutoff %>% filter(is.na(cluster)))
[1] 0

rrres_allcutoff %>% filter(ens_gene %in% markerSCs$ens_gene) %>% left_join(markerSCs)  %>% group_by(cluster,clus) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", "))
Joining, by = c("ens_gene", "ext_gene", "biotype", "chr")
`summarise()` regrouping output by 'cluster' (override with `.groups` argument)
rrres_allcutoff %>% filter(ens_gene %in% markerSCs$ens_gene) %>% left_join(markerSCs)  %>% filter(ens_gene %in% fc$ens_gene) %>% group_by(cluster,clus) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", "))
Joining, by = c("ens_gene", "ext_gene", "biotype", "chr")
`summarise()` regrouping output by 'cluster' (override with `.groups` argument)
rrres_allcutoff %>% filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3","Tpm2","Nsdhl","Myog","Ttn")) %>% group_by(cluster) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", "))
`summarise()` ungrouping output (override with `.groups` argument)
#rrres_allcutoff %>% filter(ens_gene %in% fc$ens_gene) %>% group_by(cluster) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", ")) #DEG<Day5>の遺伝子の数

rrres_allcutoff %>% filter(ens_gene %in% markerSCs$ens_gene) %>% left_join(markerSCs)  %>% group_by(cluster,clus) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", ")) %>% readr::write_csv("./Clustering_cutoff/H3mm7fig1list.csv")
Joining, by = c("ens_gene", "ext_gene", "biotype", "chr")
`summarise()` regrouping output by 'cluster' (override with `.groups` argument)
rrres_allcutoff %>% filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3","Tpm2","Nsdhl","Myog","Ttn")) %>% group_by(cluster) %>% summarise(count=n(), list=paste(ext_gene,collapse = ", "))  %>% readr::write_csv("./Clustering_cutoff/Myogeniclist.csv")
`summarise()` ungrouping output (override with `.groups` argument)

クラスタリング (cutoff cluster ASCs) の結果をGO

ASCsをクラスター毎にGO

2020.4.21, 7.17修正, 8.4修正 ver

#20200421修正 ver
#20191206修正 ver

#z_heat_label_order_cluster6 <- z_heat_label_order_cluster %>% dplyr::select(ext_gene,heatmap_order,No,cluster_6) %>% mutate(heatmap_order=as.integer(heatmap_order),No=as.integer(No),cluster_6=as.integer(cluster_6))%>% arrange(heatmap_order) %>% left_join( dplyr::select(z_timedeg_s,ens_gene,ext_gene,biotype,chr))
#_____________#

## z_heat_label_order_cluster にクラスター番号が入っている



#table_degcluster <- rrres_allcutoff  %>% f_ASCs %>% filter(!is.na(cluster)) %>% arrange(cluster, ens_gene) %>% unique() %>% filter(!is.na(ens_gene))

table_degcluster <- rrres_allcutoff   %>% filter(ens_gene %in% markerSCs$ens_gene) %>% filter(!is.na(cluster)) %>% arrange(cluster, ens_gene) %>% unique() %>% filter(!is.na(ens_gene))

degclusgene <- table_degcluster %>% group_by(cluster) %>% summarise(size=n()) %>% mutate(cluster=row_number())
`summarise()` ungrouping output (override with `.groups` argument)
table_degcluster <- table_degcluster %>% left_join(degclusgene %>% dplyr::select(cluster)) %>% arrange(cluster,ens_gene)
Joining, by = "cluster"
degclusgene
##### FDR setting ######
gofdr <- 0.1

#cluster_num <- 6
cluster_num <- nrow(degclusgene)
# 20191206修正

library(clusterProfiler)
library(org.Mm.eg.db)

folder_path <- "./Clustering_cutoff/clusterProfile/"

#-------------#
file_path <- paste(folder_path, "GO_cutoffcluster_SKMmarker_BPfdr0p1_generatio",sep="")
#file_path <- paste(folder_path, "GO_cutoffcluster_ASCs_BPfdr0p1_generatio",sep="")
filename_csv <- file_path

file_path <- paste(folder_path, "GO_cutoffcluster_SKMmarker_BPfdr0p1_generatio_cluster",sep="")
#file_path <- paste(folder_path, "GO_cutoffcluster_ASCs_BPfdr0p1_generatio_cluster",sep="")
filename_list <- file_path

print(filename_list)
[1] "./Clustering_cutoff/clusterProfile/GO_cutoffcluster_SKMmarker_BPfdr0p1_generatio_cluster"
print(filename_csv)
[1] "./Clustering_cutoff/clusterProfile/GO_cutoffcluster_SKMmarker_BPfdr0p1_generatio"
#例 filename_list <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kmeans_BPfdr0p1_generatio_cluster"
#例 filename_csv <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kemans_BPfdr0p1_generatio"
#-------------#

cluster_list <- as.list(NA) #初期化

for (i in 1:cluster_num) {
   pre_list <- as.list(NA)
   pre_list <- table_degcluster %>% filter(cluster==as.integer(i)) %>% dplyr::select(ens_gene) %>% as.list()
   names(pre_list) <- paste("ENSEMBL",as.character(i),sep="_")
 
   if (i == 1) { 
     cluster_list <- pre_list
   } 
   else cluster_list <- c(cluster_list, pre_list) 
}


for (i in 1:cluster_num) {
   print(paste(i, cluster_list[[i]] %>% tibble::enframe(name = NULL) %>% nrow(), sep=", "))
  
   pre_ego_BP <- enrichGO(gene = cluster_list[[i]],
                 OrgDb = "org.Mm.eg.db",
                 keyType = 'ENSEMBL',
                 ont = "BP",
                 pAdjustMethod = "BH",
                 pvalueCutoff  = gofdr, qvalueCutoff  = 1.0) 
   
   #20191211修正  pvalueCutoff  = fdr
   
   ## pvalue < qvalue < p.adjust ##
   # qvalueCutoff  = 0.3  qvalueCutoff  = 0.2 , qvalueCutoff  = 1.0

   #if (i == 1) { 
  #   table_ego_BP <- data.frame(pre_ego_BP) %>% mutate(cluster=as.integer(i))
  #   # リスト型からデータフレームへ変換
   #} 
   #else table_ego_BP <- table_ego_BP %>% bind_rows(data.frame(pre_ego_BP) %>% mutate(cluster=as.integer(i)))
                                                  
  if (i == 1) { 
     table_ego_BP <- data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep=""))  # リスト型からデータフレームへ変換
   } 
   else table_ego_BP <- table_ego_BP %>% bind_rows(data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep="")))
   
   #---- plot ---#
   #BPplot <- dotplot(pre_ego_BP, showCategory=30, orderBy = "Count") #clusterProfile の機能で図を描く(191106修正) wrong orderBy parameter; set to default `orderBy = "x"`
   #print(BPplot)
   #ggsave(BPplot,file=paste(filename_list,as.character(i),".png",sep=""), width = 12, height = 12, dpi = 120)
   #ggsave(BPplot,file=paste(filename_list,as.character(i),".pdf",sep=""), width = 12, height = 12, dpi = 120)
}
[1] "1, 2"
[1] "2, 17"
[1] "3, 4"
[1] "4, 4"
print(table_ego_BP %>% group_by(cluster) %>% summarise())
`summarise()` ungrouping output (override with `.groups` argument)
#------#
# データはtable_ego_BPに。

#------------------------------------------------------#
# テーブルを保存
# table_ego_BP_3t3_LRT2 <- table_ego_BP
#
table_ego_BP1 <- table_ego_BP %>% mutate(cluster=factor(cluster,c("cluster1","cluster2","cluster3","cluster4"))) %>% arrange(cluster,desc(Count)) #191106(200415), 200831 修正 

#table_ego_BP1 <- table_ego_BP %>% arrange(cluster,desc(Count))  %>% left_join(dplyr::select(degclusgene, cluster)) #191106(200415)

readr::write_csv(table_ego_BP1,paste(filename_csv,".csv",sep=""))

table_ego_BP1 %>% group_by(cluster) %>% summarise(GOterm_count=n())
`summarise()` ungrouping output (override with `.groups` argument)
# 先のテーブルのgeneIDをgene nameに置換する。(20191025)

tablego <- table_ego_BP1 %>% mutate(gene_name=geneID) %>% dplyr::select(-(qvalue))

for (i in 1:nrow(table_degcluster)) {
  tablego <- tablego %>% mutate(gene_name=gsub(gene_name, pattern=table_degcluster$ens_gene[i], replacement=table_degcluster$ext_gene[i], ignore.case = TRUE))
}

#print(tablego)

#readr::write_csv(tablego,paste(filename_csv,"_genename.csv",sep=""))

#------------------------------------------------------#

readr::write_csv(tablego,paste(filename_csv,"_genename.csv",sep=""))

SKM marker


#======== Change every data ここで順番を変更 ========#

tbl <- norm_plotlist_all %>%  filter(ens_gene %in% table_degcluster$ens_gene) %>% annotate()  %>% mutate(ext_gene=factor(ext_gene,table_degcluster$ext_gene)) 

#tbl2 <- norm_plotlist_all  %>% inner_join(e2g, by = "ens_gene") %>% filter(ext_gene %in% c("Acta1","Tpm2"))

#====================================================#

f_gene_norm <- function(x) x %>% group_by(WT_KO,Day,intact_CTX,ens_gene,ext_gene) %>% summarise(avg=mean(normalized),se=sd(normalized)/sqrt(length(normalized))) %>% ungroup()

#----#
tbl %>% group_by(WT_KO,Day,intact_CTX) %>% summarise()
`summarise()` regrouping output by 'WT_KO', 'Day' (override with `.groups` argument)
#----#

#face="italic"

### point ###
gggggpp <-ggplot(tbl,aes(Day,normalized,colour=WT_KO,group=WT_KO))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=9)+geom_line(size=1.0, aes(x=Day,y=avg,colour=WT_KO),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()
ggsave(file="./Clustering_cutoff/clusterProfile/normCount_SKMmarker.pdf", plot = gggggpp, width=22, height=10, limitsize = FALSE)
#print(gggggpp)

#======== Change every data ここで順番を変更 ========#

tbl <- norm_plotlist_all  %>% annotate() %>%  filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3","Tpm2","Nsdhl","Myog","Ttn")) 
#tbl2 <- norm_plotlist_all  %>% inner_join(e2g, by = "ens_gene") %>% filter(ext_gene %in% c("Acta1","Tpm2"))

#====================================================#

f_gene_norm <- function(x) x %>% group_by(WT_KO,Day,intact_CTX,ens_gene,ext_gene) %>% summarise(avg=mean(normalized),se=sd(normalized)/sqrt(length(normalized))) %>% ungroup()

#----#
tbl %>% group_by(WT_KO,Day,intact_CTX) %>% summarise()
`summarise()` regrouping output by 'WT_KO', 'Day' (override with `.groups` argument)
#----#

#face="italic"

### point ###
gggggpp <-ggplot(tbl,aes(Day,normalized,colour=WT_KO,group=WT_KO))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=5)+geom_line(size=1.0, aes(x=Day,y=avg,colour=WT_KO),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()
ggsave(file="./Clustering_cutoff/clusterProfile/normCount_Myo.pdf", plot = gggggpp, width=10, height=6, limitsize = FALSE)
#print(gggggpp)

#+geom_smooth(se=FALSE)

ここまで (20200807)

2群 の結果をGO

2020.4.21, 7.17修正, 8.4修正, 8.31修正ver



resUpDown <- re %>% filter(aspect=="group1_CTX_Day5_H3mm18KO_vs_WT") %>% mutate(Cluster_updown=case_when(log2FoldChange >0 ~ "Up", log2FoldChange<0 ~ "Down"),cluster=case_when(log2FoldChange >0 ~ as.integer("1"), log2FoldChange<0 ~ as.integer("2")))
resUpDown %>% group_by(aspect, Cluster_updown, cluster) %>% summarise(n())
`summarise()` regrouping output by 'aspect', 'Cluster_updown' (override with `.groups` argument)
table_degcluster <- resUpDown %>% arrange(cluster, ens_gene) %>% unique() %>% filter(!is.na(ens_gene))

degclusgene <- table_degcluster %>% group_by(cluster) %>% summarise(size=n()) %>% mutate(cluster=row_number())
`summarise()` ungrouping output (override with `.groups` argument)
table_degcluster <- table_degcluster %>% left_join(degclusgene %>% dplyr::select(cluster)) %>% arrange(cluster,ens_gene)
Joining, by = "cluster"
degclusgene
##### FDR setting ######
gofdr <- 0.1

#cluster_num <- 6
cluster_num <- nrow(degclusgene)
# 20191206修正

library(clusterProfiler)
library(org.Mm.eg.db)

folder_path <- "./2gun/clusterProfile/"

#-------------#
file_path <- paste(folder_path, "GO_2gun_BPfdr0p1_generatio",sep="")
#file_path <- paste(folder_path, "GO_cutoffcluster_ASCs_BPfdr0p1_generatio",sep="")
filename_csv <- file_path

file_path <- paste(folder_path, "GO_2gun_SKMmarker_BPfdr0p1_generatio_cluster",sep="")
#file_path <- paste(folder_path, "GO_cutoffcluster_ASCs_BPfdr0p1_generatio_cluster",sep="")
filename_list <- file_path

print(filename_list)
[1] "./2gun/clusterProfile/GO_2gun_SKMmarker_BPfdr0p1_generatio_cluster"
print(filename_csv)
[1] "./2gun/clusterProfile/GO_2gun_BPfdr0p1_generatio"
#例 filename_list <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kmeans_BPfdr0p1_generatio_cluster"
#例 filename_csv <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kemans_BPfdr0p1_generatio"
#-------------#

cluster_list <- as.list(NA) #初期化

for (i in 1:cluster_num) {
   pre_list <- as.list(NA)
   pre_list <- table_degcluster %>% filter(cluster==as.integer(i)) %>% dplyr::select(ens_gene) %>% as.list()
   names(pre_list) <- paste("ENSEMBL",as.character(i),sep="_")
 
   if (i == 1) { 
     cluster_list <- pre_list
   } 
   else cluster_list <- c(cluster_list, pre_list) 
}


for (i in 1:cluster_num) {
   print(paste(i, cluster_list[[i]] %>% tibble::enframe(name = NULL) %>% nrow(), sep=", "))
  
   pre_ego_BP <- enrichGO(gene = cluster_list[[i]],
                 OrgDb = "org.Mm.eg.db",
                 keyType = 'ENSEMBL',
                 ont = "BP",
                 pAdjustMethod = "BH",
                 pvalueCutoff  = gofdr, qvalueCutoff  = 1.0) 
   

   #20191211修正  pvalueCutoff  = fdr
   
   ## pvalue < qvalue < p.adjust ##
   # qvalueCutoff  = 0.3  qvalueCutoff  = 0.2 , qvalueCutoff  = 1.0

   #if (i == 1) { 
  #   table_ego_BP <- data.frame(pre_ego_BP) %>% mutate(cluster=as.integer(i))
  #   # リスト型からデータフレームへ変換
   #} 
   #else table_ego_BP <- table_ego_BP %>% bind_rows(data.frame(pre_ego_BP) %>% mutate(cluster=as.integer(i)))
                                                  
  if (i == 1) { 
     table_ego_BP <- data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep=""))  # リスト型からデータフレームへ変換
   } 
   else table_ego_BP <- table_ego_BP %>% bind_rows(data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep="")))
    

   #---- plot ---# (2020 0831 エラーが出るので、プロットは除く)
   #BPplot <- dotplot(pre_ego_BP, showCategory=30, orderBy = "Count") #clusterProfile の機能で図を描く(191106修正) wrong orderBy parameter; set to default `orderBy = "x"`
   #print(BPplot)
   #print("--")
   #ggsave(BPplot,file=paste(filename_list,as.character(i),".png",sep=""), width = 12, height = 12, dpi = 120)
   #print("--")
   #ggsave(BPplot,file=paste(filename_list,as.character(i),".pdf",sep=""), width = 12, height = 12, dpi = 120)
}
[1] "1, 33"
[1] "2, 217"
print(table_ego_BP %>% group_by(cluster) %>% summarise())
`summarise()` ungrouping output (override with `.groups` argument)
#------#
# データはtable_ego_BPに。

#------------------------------------------------------#
# テーブルを保存
# table_ego_BP_3t3_LRT2 <- table_ego_BP
#
table_ego_BP1 <- table_ego_BP %>% mutate(cluster=factor(cluster,c("cluster1","cluster2"))) %>% arrange(cluster,desc(Count)) #191106(200415), 200831 修正 

#table_ego_BP1 <- table_ego_BP %>% arrange(cluster,desc(Count))  %>% left_join(dplyr::select(degclusgene, cluster)) #191106(200415)

readr::write_csv(table_ego_BP1,paste(filename_csv,".csv",sep=""))


table_ego_BP1 %>% group_by(cluster) %>% summarise(GOterm_count=n())
`summarise()` ungrouping output (override with `.groups` argument)
# 先のテーブルのgeneIDをgene nameに置換する。(20191025)

tablego <- table_ego_BP1 %>% mutate(gene_name=geneID) %>% dplyr::select(-(qvalue))

for (i in 1:nrow(table_degcluster)) {
  tablego <- tablego %>% mutate(gene_name=gsub(gene_name, pattern=table_degcluster$ens_gene[i], replacement=table_degcluster$ext_gene[i], ignore.case = TRUE))
}

#------------------------------------------------------#
tablego <- tablego %>% mutate(Cluster=case_when(cluster=="cluster1" ~ "Up", cluster=="cluster2"  ~ "Down"))

readr::write_csv(tablego,paste(filename_csv,"_genename.csv",sep=""))

+++++++++++++++++++++++++

make plot

# filter GO top 20200526 ver
# 各クラスターのCount (Gene Ratio) が高いもの、p.adjustが小さいもの、pvalueが小さいものを取り出す。

# 3T3 Top5
#file_3t3 <- "/home/guestA/o70578a/akuwakado/kuwakado/BRBSeq/H3mm18_Dox_0432lane2/Final_Last_Rserver_200811/LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans_BPfdr0p1_generatio_genename.csv"
#file_3t3 <- "/home/akuwakado/makeplot_18project/Inputfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans_BPfdr0p1_generatio_genename.csv"
datamouse_rankall <- tablego %>% group_by(Cluster) %>% arrange(desc(Count), p.adjust, pvalue) %>% mutate(rank=row_number())
datamouse <- datamouse_rankall %>% filter(rank<=30)


print(datamouse)

filename <- paste("./Outputfile/","Top30__",basename(filename_csv),".csv",sep="")
print(filename)
[1] "./Outputfile/Top30__GO_2gun_BPfdr0p1_generatio.csv"
datamouse %>% readr::write_csv(filename) 

filename <- paste("./Outputfile/","RankAll__",basename(filename_csv),".csv",sep="")
print(filename)
[1] "./Outputfile/RankAll__GO_2gun_BPfdr0p1_generatio.csv"
datamouse_rankall %>% readr::write_csv(filename) 

plot mouseGO

一度に描画 (使えそう)


plot_mouse <- datamouse %>% dplyr::mutate(GeneRatio1=GeneRatio) %>% tidyr::separate(col=GeneRatio1,sep="/",into=c("count","BP_genesize")) %>% mutate(BP_genesize=as.integer(BP_genesize),Gene_ratio=Count/BP_genesize) %>% dplyr::select(-count)


xmax=0.200
xmin=0.050 #xmin=0.085

#all_break <- c(3,6,9,12,15,18)
all_break <- c(10,15,20,25,30,35,40)
sort_mouse_all <- plot_mouse %>% arrange(desc(rank))

gggU <- plot_mouse %>% arrange(desc(rank)) %>% mutate(Description =factor(Description,sort_mouse_all$Description)) %>% ggplot(aes(x=Gene_ratio, y=Description, fill=p.adjust)) + geom_point(aes(size=Count),shape = 21) + scale_size_area(breaks=all_break) + theme_bw() + theme(legend.position = "right",legend.box="horizontal",strip.text = element_text(size = 12),legend.title = element_text(size = 14),axis.title = element_text(size = 14),legend.text = element_text(size = 12),axis.text = element_text(size = 12),axis.text.x = element_text(vjust = 1),strip.background = element_blank()) + scale_fill_gradient(low = "red" , high = "blue",limits = c(0, 0.1)) + xlim(xmin,xmax) + facet_wrap(~Cluster,scales = "free_y",ncol=1)

gggU0 <- plot_mouse %>% arrange(desc(rank)) %>% mutate(Description =factor(Description,sort_mouse_all$Description))  %>% ggplot(aes(x=Gene_ratio, y=Description, fill=p.adjust)) + geom_point(aes(size=Count),shape = 21) + scale_size_area(breaks=all_break) + theme_bw() + theme(legend.position = "right",legend.box="horizontal",strip.text = element_blank(),legend.title = element_blank(),axis.title = element_blank(),legend.text = element_blank(),axis.text = element_blank(),axis.text.x = element_blank(),strip.background = element_blank()) + scale_fill_gradient(low = "red" , high = "blue",limits = c(0, 0.1)) + xlim(xmin,xmax) + facet_wrap(~Cluster,scales = "free_y",ncol=1)

print(gggU)

ggsave(gggU,file=paste("./Outputfile/","mouse_BRB0438__clusterAll_Top30_BPfdr0p1_plot1.pdf",sep=""), width = 10, height = 15, dpi = 120,limitsize = FALSE)
print(gggU0)

ggsave(gggU0,file=paste("./Outputfile/","mouse_BRB0438__clusterAll_Top30_BPfdr0p1_plot1_none.pdf",sep=""), width = 5, height = 12, dpi = 120,limitsize = FALSE)

f_DEG_in <- function(x) x %>% filter(padj<0.2)
f_DEG_out <- function(x) x %>% filter((!(padj<0.2))|is.na(padj))

re_select_plot %>% group_by(aspect) %>% summarise(n())
`summarise()` ungrouping output (override with `.groups` argument)
re_select_plot %>% f_DEG_in %>% group_by(aspect) %>% summarise(n())
`summarise()` ungrouping output (override with `.groups` argument)
re_select_plot %>% f_DEG_out %>% group_by(aspect) %>% summarise(n())
`summarise()` ungrouping output (override with `.groups` argument)
ggmaplot <- re_select_plot  %>%  ggplot(aes(groupMean,log2FoldChange))+geom_point(size=0.1, alpha = 0.5,data=f_DEG_out,color="#bdbdbd") + geom_abline(intercept=0,slope=0,colour="black",size=0.2)  + geom_vline(data = Daymean, aes(xintercept=DayMean),colour=Mean_color,size=0.2,linetype="dashed") +geom_point(aes(groupMean,log2FoldChange),size=0.3,color="#0000ff", data=f_DEG_in) + scale_x_log10() + theme_bw() + theme(legend.position = "top") + ggtitle(gggglabel) + ylim(-5.0, 5.0) + facet_wrap(~Day,ncol=1) + theme(axis.title = element_text(size=15),axis.text = element_text(size=10),axis.text.x = element_text(hjust = 0.5,vjust=1.0), legend.position = "right", strip.text=element_text(size=15),strip.background = element_blank(),title = element_text(size=8))

#+ scale_color_manual(values = c("#ff0000","#0000ff","#000000")) 

ggsave(file="./2gun/DEG_DayAll_MAplot_Mean.pdf", plot = ggmaplot, width = 7, height = 8, dpi = 120)
plot(ggmaplot)

NA
NA
Ci0tLQp0aXRsZTogIltGaW5hbCAyMDA4MzFdIEJSQjA0MzhfUUNfdG1wbF92Nl9ub3VtaV8xOTA1MTUtSDNtbTE4S09fQ1RYXzIwMDgzMV8yMDA4MzFvbmx5ICgyMDA1MjN2ZXLjga7op6PmnpDntprjgY0pIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHllcwogIHBkZl9kb2N1bWVudDogCiAgICBrZWVwX3RleDogeWVzCiAgICBsYXRleF9lbmdpbmU6IGx1YWxhdGV4Ci0tLQoKIyMjIFNldHVwCgpgYGB7ciBsaWJyYXJpZXMsbWVzc2FnZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHB1cnJyKQoKbGlicmFyeShTdW1tYXJpemVkRXhwZXJpbWVudCkKc291cmNlKCIvaG9tZS9ndWVzdEEvbjcwMjc1Yi93b3JrL3JzY3JpcHRzL2dlb21Ob3JtLlIiKSAjSVRPCiNzb3VyY2UoIi9ob21lL2l0b19taXJyb3IvbjcwMjc1Yi93b3JrL3JzY3JpcHRzL2dlb21Ob3JtLlIiKQoKIyBIZWxwZXIgZnVuY3Rpb24KI2dncG9pbnRzIDwtIGZ1bmN0aW9uKHgsLi4uKSAKIyAgZ2dwbG90KHgsLi4uKSArIGdlb21fcG9pbnQoc2l6ZT0zLHN0cm9rZT0xKSArCiMgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChzaXplPTQpICsgdGhlbWVfbWluaW1hbCgpICsgbXljb2xvcgoKIyMg44Op44OZ44Or44GC44KKCmdncG9pbnRzIDwtIGZ1bmN0aW9uKHgsLi4uKSAKICBnZ3Bsb3QoeCwuLi4pICsgZ2VvbV9wb2ludChzdHJva2U9MSkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChzaXplPTQpICsgdGhlbWVfbWluaW1hbCgpICsgbXljb2xvcgoKIyMg44Op44OZ44Or44Gq44GXCiNnZ3BvaW50cyA8LSBmdW5jdGlvbih4LC4uLikgCiMgIGdncGxvdCh4LC4uLikgKyBnZW9tX3BvaW50KHN0cm9rZT0xKSArIHRoZW1lX21pbmltYWwoKSArIG15Y29sb3IKCgpwcmludChTeXMuRGF0ZSgpKQpwcmludChzZXNzaW9uSW5mbygpLGxvY2FsZT1GQUxTRSkKCnNlbGVjdCA8LSBkcGx5cjo6c2VsZWN0CmNvdW50IDwtIGRwbHlyOjpjb3VudApyZW5hbWUgPC0gZHBseXI6OnJlbmFtZQpgYGAKCgojIyBCUkIgbW91c2UgQ1RYIHJlc3VsdAoKCiMjIyBQYXJhbWV0ZXJzCgoqbW9kaWZ5IGhlcmUqCgpgYGB7ciBwYXJhbXN9CiMgRmlsZXMKIyBJVE8KCmRlZnRhYmxlIDwtICJ+L2FrdXdha2Fkby9rdXdha2Fkby9CUkJTZXEvSDNtbTE4S09fYW5kX0gzcDNLT18wNDM4L1Jfc2VydmVyX19tb3VzZV9IM21tMThLT19DVFhfXzE5MDkyNC0vZGVmdGFibGVfbnVjbGVvc29tZXZlcl9CUkJfbm91bWlfSDNtbTE4S09fYW5kX0gzcDNLT18wNDM4XzE5MDUxNS1IM21tMThLT19DVFhfUzItRGF5MF9TM18yMDA1MjNtb2RpZi50eHQiCgojIOOCq+OCpuODs+ODiOOBq+OBr+OAgeOAjC9ob21lL2l0b19taXJyb3IvbzcwNTc4YS9ha3V3YWthZG8va3V3YWthZG8vQlJCU2VxL0gzbW0xOEtPX2FuZF9IM3AzS09fMDQzOC8xOTA1MTUtSDNtbTE4S09fQ1RYX1MyX3RyaW1tZWQuY291bnRzLnR4dC5neuOAjeetieOCkuS9v+eUqOOBmeOCi+OCiOOBhuOBq+WkieabtOOAggoKCnVzZSA8LSBxdW8oc2FtcGxlIT0iSDNtbTE4S08tRGF5NS1pbnRhY3QtbTIiKSAjMjAyMDA1MjPjga/jgZPjgaHjgokKdXNlIDwtIHF1bygoc2FtcGxlIT0iSDNtbTE4S08tRGF5NS1pbnRhY3QtbTIiKSYoaW50YWN0X0NUWCE9ImludGFjdCIpKSAjMjAyMDA4MzHlpInmm7TjgIAj44GT44Gh44KJ44Gr44GX44Gm44KC44CBZ3JvdXAxX0NUWF9EYXk1X0gzbW0xOEtPX3ZzX1dU44GuREVH44Gv44G744Go44KT44Gp5aSJ44KP44KJ44Gq44GECgoKIyBTcGVjaWVzIHNwZWNpZmljIHBhcmFtZXRlcnMKc3BlY2llcyA8LSAiTXVzIG11c2N1bHVzIgpiaW9tYXJ0YW5uIDwtICJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIgptYXhjaHJvbSA8LSAxOSAjIDE5OiBtb3VzZSwgMjI6IGh1bWFuCgoKIyBHcmFwaGljcwojIGFlc3RoZXRpYyBtYXBwaW5nIG9mIGxhYmVscwoKbXlhZXMgPC0gYWVzKGNvbG91cj1XVF9LT19pbnRhY3RfQ1RYLCBzaGFwZT1EYXksIGxhYmVsPWZfbSkgI+OCteOCpOOCuuOCkuWkieOBiOOBmu+8gwoKI3R5cGVfRG94cGx1c192c19taW51cyA9IGMoInR5cGUiLCAiRG94cGx1cyIsICJEb3htaW51cyIpCiNncm93dGhfRGlmZjBoX3ZzX1VJID0gYygiZ3Jvd3RoIiwiRGlmZjBoIiwiVUkiKQoKCiNmaWxlCXNhbXBsZQlncm91cAlncm91cDEJIFdUX0tPX2ludGFjdF9DVFgJYmFyY29kZQkgV1RfS08JRGF5CWludGFjdF9DVFgJZl9tCXJlcGxpY2F0ZQoKI2ZpbGUJc2FtcGxlCWdyb3VwCWdyb3VwMQliYXJjb2RlCSBXVF9LTwlEYXkJaW50YWN0X0NUWAlmX20JcmVwbGljYXRlCgoKI3R5cGUsdGltZSxpbnRhY3RfQ1RYLCBmX20KCiMgY29sb3IgcGFsZXR0ZSBvZiBwb2ludHM6IFNlZSB2aWduZXR0ZSgiZ2dzY2kiKQpteWNvbG9yIDwtIGdnc2NpOjpzY2FsZV9jb2xvcl9hYWFzKCkKCiNteWNvbG9yIDwtIGdnc2NpOjpzY2FsZV9jb2xvcl9kMygiY2F0ZWdvcnkyMCIpICMgY29sb3IgcGFsZXR0ZSBvZiBwb2ludHMKCiNteWFlczIgPC0gYWVzKGNvbG91cj10eXBlKSAja3V3YSBhZGQKI215YWVzMiA8LSBhZXMoY29sb3VyPWdyb3d0aCxzaGFwZT10eXBlKSNrdXdhIGFkZAojbXlhZXMyIDwtIGFlcyhjb2xvdXI9dGltZSxzaGFwZT10eXBlLHNpemU9Y291bnQpICPjg6njg5njg6vjgaoKI215YWVzMiA8LSBhZXMoY29sb3VyPXRpbWUsc2hhcGU9aW50YWN0X0NUWCxzaXplPXR5cGUsbGFiZWw9Zl9tKSAj44Op44OZ44Or44Gq44GXCiNteWFlczIgPC0gYWVzKGNvbG91cj1XVF9LTyxzaGFwZT1pbnRhY3RfQ1RYLHNpemU9Zl9tLGxhYmVsPURheSkKCgojIFBDQS9VTUFQCnNjYWxlcm93cyA8LSBUUlVFICMgZ2VuZS13aXNlIHNjYWxpbmcgKHBhdHRlcm4gaXMgdGhlIG1hdHRlcj8pCm50b3AgPC0gNTAwICMgbnVtYmVyIG9mIHRvcC1uIGdlbmVzIHdpdGggaGlnaCB2YXJpYW5jZQpzZWVkIDwtIDEyMyAjIHNldCBhbm90aGVyIG51bWJlciBpZiBVTUFQIGxvb2tzIG5vdCBnb29kCm5fbmVpIDwtIDYgICMgbnVtYmVyIG9mIG5laWdoYm9yaW5nIGRhdGEgcG9pbnRzIGluIFVNQVAgI+OBk+OBk+OCkuOBqeOBhuOBl+OBn+OCieOBhOOBhO+8nwoKCiMgREVTZXEyCiNtb2RlbCA8LSB+Z3JvdXBuK2xlYWQgI2RhdGXjgoLov73liqAKI21vZGVsIDwtIH5sZWcgKyBlbnp5bWUgKyBsZWc6ZW56eW1lCiNtb2RlbCA8LSB+dHlwZStncm93dGgjK3R5cGU6Z3Jvd3RoCiNtb2RlbCA8LSB+Z3JvdXArbGVhZAoKCiNtb2RlbCA8LSB+Z3JvdXAKI21vZGVsIDwtIH50eXBlK2dyb3d0aCt0eXBlOmdyb3d0aCAj44GT44KM44Gn44Gv55u45LqS5L2c55So44GM5YWl44Gj44Gm44GE44Gq44GECiNtb2RlbCA8LSB+dHlwZStncm93dGggI+OBk+OCjOOBp+OBr+ebuOS6kuS9nOeUqOOBjOWFpeOBo+OBpuOBhOOBquOBhAojbW9kZWwgPC0gfmdyb3VwCgptb2RlbCA8LSB+Z3JvdXAxCgojZmRyIDwtIDAuMSAjIGFjY2VwdGFibGUgZmFsc2UgZGlzY292ZXJ5IHJhdGUKZmRyIDwtIDAuMiAjIGFjY2VwdGFibGUgZmFsc2UgZGlzY292ZXJ5IHJhdGUKCmxmY3RocmV0aCA8LSBsb2cyKDEpICMgdGhyZXNob2xkIGluIGFicyhsb2cyRkMpCiMgY29udHJvbHMgc2hvdWxkIGJlIHBsYWNlZCBpbiB0aGUgcmlnaHQKY29udHJhc3QgPC0gbGlzdCgKCiAgSW50ZXJjZXB0ID0gbGlzdCgiSW50ZXJjZXB0IiksCiAgZ3JvdXAxX1NLTV9EYXkwX0gzbW0xOEtPX3ZzX1dUID0gYygiZ3JvdXAxIiwgIkgzbW0xOEtPX0RheTBfU0tNIiwgIldUX0RheTBfU0tNIiksCiAgZ3JvdXAxX0NUWF9EYXk1X0gzbW0xOEtPX3ZzX1dUID0gYygiZ3JvdXAxIiwgIkgzbW0xOEtPX0RheTVfQ1RYIiwgIldUX0RheTVfQ1RYIiksCiAgZ3JvdXAxX0NUWF9EYXkxNF9IM21tMThLT192c19XVCA9IGMoImdyb3VwMSIsICJIM21tMThLT19EYXkxNF9DVFgiLCAiV1RfRGF5MTRfQ1RYIikKCiAgI2dyb3VwMV9pbnRhY3RfRGF5NV9IM21tMThLT192c19XVCA9IGMoImdyb3VwMSIsICJIM21tMThLT19EYXk1X2ludGFjdCIsICJXVF9EYXk1X2ludGFjdCIpLAogICNncm91cDFfaW50YWN0X0RheTE0X0gzbW0xOEtPX3ZzX1dUID0gYygiZ3JvdXAxIiwgIkgzbW0xOEtPX0RheTE0X2ludGFjdCIsICJXVF9EYXkxNF9pbnRhY3QiKQoKKQoKCnNvcnRfbW91c2UgPC0gYygKICAiV1QtZjE3OS1TS00iLCJXVC1mODcwLVNLTSIsIldULW0xODEtU0tNIiwKICAiV1QtRGF5NS1DVFgtZjEiLCJXVC1EYXk1LUNUWC1mMiIsIldULURheTUtQ1RYLWYzIiwiV1QtRGF5NS1DVFgtbTEiLAogICJXVC1EYXkxNC1DVFgtZjEiLCJXVC1EYXkxNC1DVFgtZjIiLCJXVC1EYXkxNC1DVFgtZjMiLCJXVC1EYXkxNC1DVFgtbTEiLCJXVC1EYXkxNC1DVFgtbTIiLAogICJIM21tMThLTy1mMTc3LVNLTSIsIkgzbW0xOEtPLWY4NjktU0tNIiwiSDNtbTE4S08tbTE4Mi1TS00iLAogICJIM21tMThLTy1EYXk1LUNUWC1mMSIsIkgzbW0xOEtPLURheTUtQ1RYLWYyIiwiSDNtbTE4S08tRGF5NS1DVFgtZjMiLCJIM21tMThLTy1EYXk1LUNUWC1tMSIsIkgzbW0xOEtPLURheTUtQ1RYLW0yIiwKICAiSDNtbTE4S08tRGF5MTQtQ1RYLWYxIiwiSDNtbTE4S08tRGF5MTQtQ1RYLWYyIiwiSDNtbTE4S08tRGF5MTQtQ1RYLWYzIiwiSDNtbTE4S08tRGF5MTQtQ1RYLW0xIiwiSDNtbTE4S08tRGF5MTQtQ1RYLW0yIgogIAogICMiV1QtRGF5NS1pbnRhY3QtZjEiLCJXVC1EYXk1LWludGFjdC1mMiIsIldULURheTUtaW50YWN0LWYzIiwiV1QtRGF5NS1pbnRhY3QtbTEiLAogICMiV1QtRGF5MTQtaW50YWN0LWYxIiwiV1QtRGF5MTQtaW50YWN0LWYyIiwiV1QtRGF5MTQtaW50YWN0LWYzIiwiV1QtRGF5MTQtaW50YWN0LW0xIiwiV1QtRGF5MTQtaW50YWN0LW0yIiwKICAjIkgzbW0xOEtPLURheTUtaW50YWN0LWYxIiwiSDNtbTE4S08tRGF5NS1pbnRhY3QtZjIiLCJIM21tMThLTy1EYXk1LWludGFjdC1mMyIsIkgzbW0xOEtPLURheTUtaW50YWN0LW0xIiwKICAjIkgzbW0xOEtPLURheTE0LWludGFjdC1mMSIsIkgzbW0xOEtPLURheTE0LWludGFjdC1mMiIsIkgzbW0xOEtPLURheTE0LWludGFjdC1mMyIsIkgzbW0xOEtPLURheTE0LWludGFjdC1tMSIsIkgzbW0xOEtPLURheTE0LWludGFjdC1tMiIgCikKCmBgYAoKCgojIyMgUmV0cmlldmUgQmlvbWFydAoKYGBge3IgYmlvbWFydCwgY2FjaGU9VFJVRX0KaWYoIWV4aXN0cygiZTJnIikpewogICNlbnNlbWJsIDwtIGJpb21hUnQ6OnVzZU1hcnQoIkVOU0VNQkxfTUFSVF9FTlNFTUJMIixob3N0PSJhc2lhLmVuc2VtYmwub3JnIikKICBlbnNlbWJsIDwtIGJpb21hUnQ6OnVzZU1hcnQoIkVOU0VNQkxfTUFSVF9FTlNFTUJMIixob3N0PSJ1c3dlc3QuZW5zZW1ibC5vcmciKQogIG1hcnQgPC0gYmlvbWFSdDo6dXNlRGF0YXNldChiaW9tYXJ0YW5uLG1hcnQ9ZW5zZW1ibCkKICBlMmcgPC0gYmlvbWFSdDo6Z2V0Qk0oYXR0cmlidXRlcz1jKCJlbnNlbWJsX2dlbmVfaWQiLCJleHRlcm5hbF9nZW5lX25hbWUiLAogICAgImdlbmVfYmlvdHlwZSIsImNocm9tb3NvbWVfbmFtZSIpLCBtYXJ0PW1hcnQpICU+JSBhc190aWJibGUgJT4lCiAgcmVuYW1lKAogICAgZW5zX2dlbmUgPSBlbnNlbWJsX2dlbmVfaWQsCiAgICBleHRfZ2VuZSA9IGV4dGVybmFsX2dlbmVfbmFtZSwKICAgIGJpb3R5cGUgPSBnZW5lX2Jpb3R5cGUsCiAgICBjaHIgPSBjaHJvbW9zb21lX25hbWUKICApCn0KYW5ub3RhdGUgPC0gcGFydGlhbChyaWdodF9qb2luLGUyZyxieT0iZW5zX2dlbmUiKQoKIy0tLS0tIwpucm93KGUyZykKI3JlYWRyOjp3cml0ZV9jc3YoZTJnLCJlbnNlbWJsZV9saXN0X2FzaWFfZmluMjAwODMxLmNzdiIpCnJlYWRyOjp3cml0ZV9jc3YoZTJnLCJlbnNlbWJsZV9saXN0X3Vzd2VzdF9maW4yMDA4MzEuY3N2IikKYGBgCgojIyMgTG9hZCBjb3VudHMKCmBgYHtyIGxvYWRVTUl9CmRlZiA8LSByZWFkcjo6cmVhZF90c3YoZGVmdGFibGUpICU+JSBmaWx0ZXIoISF1c2UpCnByaW50KGRlZikKCmRlZiRzYW1wbGUKbGVuZ3RoKHNvcnRfbW91c2UpCiMjIyMtLS0gTmV3IC0tLSMjIyMgKG5vIFVNSSA/KQojIFNldCByZWZlcmVuY2UgbGV2ZWxzIGFjY29yZGluZyB0byB0aGUgY29udHJhc3QKZm9yKHggaW4ga2VlcChjb250cmFzdCxpcy5jaGFyYWN0ZXIpKQogIGRlZltbeFsxXV1dIDwtIHJlbGV2ZWwoZmFjdG9yKGRlZltbeFsxXV1dKSx4WzNdKQoKdW1pIDwtIGRlZiRmaWxlICU+JSB1bmlxdWUgJT4lIHRpYmJsZShmaWxlPS4pICU+JSAKICBkcGx5cjo6bXV0YXRlKGRhdGE9bWFwKGZpbGUscmVhZHI6OnJlYWRfdHN2LHByb2dyZXNzPUZBTFNFKSkgJT4lCiAgdW5uZXN0KCkgJT4lIGRwbHlyOjpyZW5hbWUoYmFyY29kZT1jZWxsKSAlPiUKICBkcGx5cjo6aW5uZXJfam9pbihzZWxlY3QoZGVmLGZpbGUsYmFyY29kZSxzYW1wbGUpLC4sYygiZmlsZSIsImJhcmNvZGUiKSkgJT4lCiAgc2VsZWN0KC1maWxlLC1iYXJjb2RlKSAlPiUgZHBseXI6OnJlbmFtZShlbnNfZ2VuZT1nZW5lKQoKcHJpbnQodW1pKQoKIyMgc2FtcGxlLCBiYXJjb2RlLCBmaWxlIOOCkuW/mOOCjOOBmuOBq++8gQoKbWF0IDwtIHVtaSAlPiUgYW5ub3RhdGUgJT4lCiAgZHBseXI6Om11dGF0ZShjaHI9ZmFjdG9yKGNocixjKDE6bWF4Y2hyb20sIlgiLCJZIiwiTVQiKSkpICU+JQogIGZpbHRlcighaXMubmEoY2hyKSkgJT4lIHNwcmVhZChzYW1wbGUsY291bnQsZmlsbD0wKQoKIyMgdG8gY2hlY2sgcmVhZCB2aWFzLCB0aGlzIGFkZCByZWFkIG51bWJlciBhcyAibiIgY29sdW1uICgyMDE5LzQvMTkpCmRlZiA8LSB1bWkgJT4lIGNvdW50KHNhbXBsZSx3dD1jb3VudCkgJT4lIGRwbHlyOjppbm5lcl9qb2luKGRlZiwuKSAlPiUgZHBseXI6OnJlbmFtZShjb3VudD1uKQojIyMjLS0tLS0tLS0tLS0jIyMjIAoKCgoKIyBTZXQgcmVmZXJlbmNlIGxldmVscyBhY2NvcmRpbmcgdG8gdGhlIGNvbnRyYXN0CiNmb3IoeCBpbiBrZWVwKGNvbnRyYXN0LGlzLmNoYXJhY3RlcikpCiMgIGRlZltbeFsxXV1dIDwtIHJlbGV2ZWwoZmFjdG9yKGRlZltbeFsxXV1dKSx4WzNdKQoKI3VtaSA8LSBkZWYkZmlsZSAlPiUgdW5pcXVlICU+JSB0aWJibGUoZmlsZT0uKSAlPiUgCiMgIG11dGF0ZShkYXRhPW1hcChmaWxlLHJlYWRyOjpyZWFkX3Rzdixwcm9ncmVzcz1GQUxTRSkpICU+JQojICB1bm5lc3QoKSAlPiUgZHBseXI6OnJlbmFtZShiYXJjb2RlPWNlbGwpICU+JQojICBpbm5lcl9qb2luKHNlbGVjdChkZWYsZmlsZSxiYXJjb2RlLHNhbXBsZSksLixjKCJmaWxlIiwiYmFyY29kZSIpKSAlPiUKIyAgc2VsZWN0KC1maWxlLC1iYXJjb2RlKSAlPiUgZHBseXI6OnJlbmFtZShlbnNfZ2VuZT1nZW5lKQoKI21hdCA8LSB1bWkgJT4lIGFubm90YXRlICU+JQojICBtdXRhdGUoY2hyPWZhY3RvcihjaHIsYygxOm1heGNocm9tLCJYIiwiWSIsIk1UIikpKSAlPiUKIyAgZmlsdGVyKCFpcy5uYShjaHIpKSAlPiUgc3ByZWFkKHNhbXBsZSxjb3VudCxmaWxsPTApCgpwcmludChtYXQpCgojIyB0byBjaGVjayByZWFkIHZpYXMsIHRoaXMgYWRkIHJlYWQgbnVtYmVyIGFzICJuIiBjb2x1bW4gKDIwMTkvNC8xOSkKI2RlZiA8LSB1bWkgJT4lIGNvdW50KHNhbXBsZSx3dD1jb3VudCkgJT4lIGlubmVyX2pvaW4oZGVmLC4pICU+JSBkcGx5cjo6cmVuYW1lKGNvdW50PW4pCgpwcmludChkZWYpCgoKIyM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jIwojIOeiuuiqjSAoMjAxOTEyMDQpIO+8kuOBpOOBruWApOOBr+S4gOe3kuOBi++8nwojIOeUn+OBruODh+ODvOOCv+OCq+OCpuODs+ODiOS4reOBrumBuuS8neWtkOe3j+aVsAoKdW1pICU+JSBncm91cF9ieShlbnNfZ2VuZSkgJT4lIHN1bW1hcmlzZSAlPiUgbnJvdygpCgp1bWkgJT4lIHNwcmVhZChzYW1wbGUsY291bnQsZmlsbD0wKSAlPiUgbnJvdygpCgptYXQgJT4lIG5yb3coKQptYXQgJT4lIGZpbHRlcihjaHIhPSJNVCIpICU+JSBucm93KCkgIyBNVOOBquOBlwoKIyBtYXTjgafjga/jgIFjaHLnrYnjgYzkuI3mmI7jgarjgoLjga7jga/nnIHjgYTjgabjgYTjgovjgIIKIyBERUfjgafjga/jgIHjgZXjgonjgatNVOOCguecgeOBhOOBpuOBhOOCi+OAggojIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMjCgoKYGBgCgojIyMgUmVhZHMgYnJlYWtkb3duCgojIyMjIFRvdGFsIHJlYWRzCgpgYGB7ciB0b3RhbFJlYWRzLCBmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTV9CmJ5Y2hyIDwtIG1hdCAlPiUgc2VsZWN0KC0oMTozKSkgJT4lCiAgZ2F0aGVyKCJzYW1wbGUiLCJjb3VudCIsLWNocikgJT4lCiAgZ3JvdXBfYnkoY2hyLHNhbXBsZSkgJT4lIHN1bW1hcmlzZSh0b3RhbD1zdW0oY291bnQpKSAlPiUgdW5ncm91cAoKZ2dwbG90KGJ5Y2hyLGFlcyhyZW9yZGVyKHNhbXBsZSxkcGx5cjo6ZGVzYyhzYW1wbGUpKSx0b3RhbC8xZTYsZmlsbD1jaHIpKSArCiAgdGhlbWVfbGluZWRyYXcoKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKwogIHhsYWIoInNhbXBsZSIpICsgeWxhYigibWlsbGlvbiByZWFkcyIpICsgZ2dzY2k6OnNjYWxlX2ZpbGxfaWd2KCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KGxldmVscyhzYW1wbGUpKSkKCgpgYGAKCiMjIyMgQmlvdHlwZQoKYGBge3IgYmlvdHlwZSxmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTd9CmJ0IDwtIG1hdCAlPiUgc2VsZWN0KC1jKDEsMiw0KSkgJT4lIGdyb3VwX2J5KGJpb3R5cGUpICU+JQogIHN1bW1hcmlzZV9hbGwoc3VtKSAlPiUgZmlsdGVyX2F0KC0xLGFueV92YXJzKC4gPiAxMDAwKSkKYnQgJT4lIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJiaW90eXBlIikgJT4lCiAgYXMubWF0cml4ICU+JSB0ICU+JSBtb3NhaWNwbG90KGxhcz0yLHNoYWRlPVRSVUUpCmBgYAoKIyMjIENvcnJlbGF0aW9ucwoKZHJvcCByb3dzIHdpdGggYWxsIDAgLT4gKzEvMiAtPiBnZW9tLnNjYWxlIC0+IGxvZyAtPiBQZWFyc29uJ3MKCmBgYHtyIG1ha2VtYXQsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9N30KbWF0ZiA8LSBtYXQgJT4lIGZpbHRlcihjaHIhPSJNVCIpICU+JSBmaWx0ZXJfYXQoLSgxOjQpLGFueV92YXJzKC4gPiAwKSkKWCA8LSBtYXRmICU+JSBzZWxlY3QoLSgxOjQpKSAlPiUgYXMubWF0cml4CnJvd25hbWVzKFgpIDwtIG1hdGYkZW5zX2dlbmUKbFggPC0gbG9nKGdzY2FsZShYKzAuNSkpClIgPC0gY29yKGxYKTsgZGlhZyhSKSA8LSBOQQpwaGVhdG1hcDo6cGhlYXRtYXAoUixjb2xvcj12aXJpZGlzOjp2aXJpZGlzKDI1NikpCmBgYAoKIyMjIERpbWVuc2lvbiByZWR1Y3Rpb24KCmBgYHtyIFBDQSxmaWcud2lkdGg9NCxmaWcuaGVpZ2h0PTN9CiMgc2V0IHNjYWxlPVRSVUUgaWYgdGhlIHBhdHRlcm5zIChub3QgbGV2ZWwpIGlzIHRoZSBtYXR0ZXIKcCA8LSBwcmNvbXAodChsWFtyYW5rKC1hcHBseShsWCwxLHZhcikpIDw9IG50b3AsXSksc2NhbGU9c2NhbGVyb3dzLGNlbnRlcj1UUlVFKQpzY3JlZXBsb3QocCxsYXM9MixtYWluPSJJbXBvcnRhbmNlIikKcHJpbnQoc3VtbWFyeShwKSRpbXBbLHNlcShtaW4oMTAsbmNvbChYKSkpXSkKYGBgCgpgYGB7ciBtYWtlc2NvcmVERn0KbGFiZWwgPC0gZGVmICU+JSBmaWx0ZXIoc2FtcGxlICVpbiUgY29sbmFtZXMoWCkpCmRmIDwtIGRhdGEuZnJhbWUocCR4KSAlPiUgYXNfdGliYmxlKHJvd25hbWVzPSJzYW1wbGUiKSAlPiUKICBpbm5lcl9qb2luKGxhYmVsLC4pICU+JSBzZWxlY3QoLWZpbGUpCgpwcmludChkZikKYGBgCgpgYGB7ciBwcm94aW1pdHksZmlnLndpZHRoPTYsZmlnLmhlaWdodD00fQpnZ3BvaW50cyhkZixtb2RpZnlMaXN0KGFlcyhQQzEsUEMyKSxteWFlcykpCgoKIy0tLS0tIG51bGVvc29tZeOBp3V3b3Tjga7oqr/lrZDjgYzmgqrjgYTjga7jgafmtojjgZkgMTkwODI3IC0tLS0tIwoKc2V0LnNlZWQoc2VlZCkKdW0gPC0gdXdvdDo6dW1hcChwJHgsbl9uZWksMikKZGYgPC0gYXNfdGliYmxlKHVtKSAlPiUgcmVuYW1lKFVNQVAxPVYxLFVNQVAyPVYyKSAlPiUgYmluZF9jb2xzKGRmKQpnZ3BvaW50cyhkZixtb2RpZnlMaXN0KGFlcyhVTUFQMSxVTUFQMiksbXlhZXMpKQoKcHJpbnQoZGYpCgojIyAga3V3YWthZG8g5aSJ5pu0ICMjCiNnZ3BvaW50cyA8LSBmdW5jdGlvbih4LC4uLikgCiMgIGdncGxvdCh4LC4uLikgKyBnZW9tX3BvaW50KHN0cm9rZT0xKSArIHRoZW1lX21pbmltYWwoKSArIG15Y29sb3IKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCgojZ2dwb2ludHMoZGYsbW9kaWZ5TGlzdChhZXMoUEMxLFBDMiksbXlhZXMyKSkKI3NldC5zZWVkKHNlZWQpCiN1bSA8LSB1d290Ojp1bWFwKHAkeCxuX25laSwyKQojZGYgPC0gYXNfdGliYmxlKHVtKSAlPiUgcmVuYW1lKFVNQVAxPVYxLFVNQVAyPVYyKSAlPiUgYmluZF9jb2xzKGRmKQojZ2dwb2ludHMoZGYsbW9kaWZ5TGlzdChhZXMoVU1BUDEsVU1BUDIpLG15YWVzMikpCiMjICMjICMjICMjCmBgYAoKIyMjIERFU2VxMgoKIyMjIyBGaXQgbW9kZWwKCmBgYHtyIGRlc2VxMn0KZGRzIDwtIERFU2VxMjo6REVTZXFEYXRhU2V0RnJvbU1hdHJpeChYWyxsYWJlbCRzYW1wbGVdLGxhYmVsLG1vZGVsKQpkZHMgPC0gREVTZXEyOjpERVNlcShkZHMpCgoKIz09PT09IwoKZGRzIDwtIERFU2VxMjo6ZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpCm5vcm0gPC0gREVTZXEyOjpjb3VudHMoZGRzLG5vcm1hbGl6ZWQ9VFJVRSkgI0RFR+OCkuWPluOBo+OBn+W+jOOBruOCr+ODqeOCueOCv+ODquODs+OCsOOBq+S9v+OBhuOAggoKbm9ybWFsaXplZGNvdW50IDwtIGFzLmRhdGEuZnJhbWUobm9ybSkgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJlbnNfZ2VuZSIpICU+JSBhc190aWJibGUKcmVhZHI6OndyaXRlX2Nzdihub3JtYWxpemVkY291bnQsICIuL0JSQjA0MzhyZV9IM21tMThLT19tb3VzZV9DVFhfbm9ybWFsaXplZGNvdW50X2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKCm5vcm1fZ2VuZSA8LSBub3JtYWxpemVkY291bnQgJT4lIGlubmVyX2pvaW4oZTJnKQpyZWFkcjo6d3JpdGVfY3N2KG5vcm1fZ2VuZSwgIi4vQlJCMDQzOHJlX0gzbW0xOEtPX21vdXNlX0NUWF9ub3JtYWxpemVkY291bnRfZ2VuZW5hbWVfZmluMjAwNTIzX2FkZDIwMDgzMS5jc3YiKQpucm93KG5vcm1fZ2VuZSkKbmNvbChub3JtX2dlbmUpCgojIyMjLS0tICsgc2l6ZSBmYWN0b3JzIOOCkuabuOOBjeWHuuOBlyAtLS0tLS0tLS0tLS0tLS0tLS0jIyMjCmFzLmRhdGEuZnJhbWUoREVTZXEyOjpzaXplRmFjdG9ycyhkZHMpKSAgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKSAlPiUgcmVhZHI6OndyaXRlX2NzdigiLi9CUkIwNDM4cmVfSDNtbTE4S09fbW91c2VfQ1RYX3NpemVmYWN0b3JzX2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKCgoKI2NvdW50X2RkcyA8LSBlc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKI2NvdW50cyhjb3VudF9kZHMsIG5vcm1hbGl6ZWQ9VFJVRSkKYGBgCnZzdCA9PiB6IHNjb3JlCgoKYGBge3Igc2V0dXAgbWF0cml4IERlc2VxMiBwYXJ0NCAyMDA3MDcgMjAwODMxYWRkfQoKdnNkIDwtIERFU2VxMjo6dnN0KGRkcykgI25vcm1hbGl6ZWQgY291bnTjgYzlhaXjgaPjgabjgYTjgovjgIIodnN044GLcmxvZykKI1hkIDwtIHN1bW1hcmlzZWRFeHBlcmltZW50Ojphc3NheSh2c2QpICMg5YWo44Gm6YG45oqeKDIwMDMyNikgMjAxOTA5MjDjgpLlhYPjgasgKDE5MTAyNCkKWGQgPC0gU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZCkgIyDlhajjgabpgbjmip4oMjAwMzI2KSAyMDE5MDkyMOOCkuWFg+OBqyAoMTkxMDI0KQpYcyA8LSBYZCAlPiUgdCAlPiUgc2NhbGUgJT4lIHQKCnpzY29yZSA8LSBYcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiZW5zX2dlbmUiKSAlPiUgYXNfdGliYmxlCnpzY29yZV90eXBlIDwtIHpzY29yZSAgJT4lIGFubm90YXRlICU+JSBkcGx5cjo6c2VsZWN0KCJlbnNfZ2VuZSIsImV4dF9nZW5lIiwgImJpb3R5cGUiLCJjaHIiLCBhbGxfb2Yoc29ydF9tb3VzZSkpCgoKCnJlYWRyOjp3cml0ZV9jc3YoenNjb3JlLCAiQlJCMDQzOHJlX0gzbW0xOEtPX21vdXNlX0NUWF96c2NvcmVfYWxsX2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKcmVhZHI6OndyaXRlX2Nzdih6c2NvcmVfdHlwZSwgIkJSQjA0MzhyZV9IM21tMThLT19tb3VzZV9DVFhfenNjb3JlX3R5cGVfYWxsX2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKCm5yb3coenNjb3JlX3R5cGUpCgpgYGAKCiMjIyMgRGlhZ25vc3RpY3MgcGxvdAoKYGBge3IgZGlhZ25vc3RpY3MsZmlnLndpZHRoPTcsZmlnLmhlaWdodD01fQpERVNlcTI6OnNpemVGYWN0b3JzKGRkcykgJT4lCiAge3RpYmJsZShzYW1wbGU9bmFtZXMoLiksc2l6ZUZhY3Rvcj0uKX0gJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUsc2l6ZUZhY3RvcikpICsgdGhlbWVfbWluaW1hbCgpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgY29vcmRfZmxpcCgpCkRFU2VxMjo6cGxvdERpc3BFc3RzKGRkcykKYGBgCgojIyMjIEV4dHJhY3QgcmVzdWx0cwoKYGBge3IgZXh0cmFjdFJlc30KcmVzIDwtIG1hcHBseShmdW5jdGlvbih4KQogIERFU2VxMjo6cmVzdWx0cyhkZHMseCxsZmNUaHJlc2hvbGQ9bGZjdGhyZXRoLGFscGhhPWZkcikKLGNvbnRyYXN0KQoKcHJpbnQoZmRyKQoKI3JlIDwtIG1hcChyZXMsYXNfdGliYmxlLHJvd25hbWVzPSJlbnNfZ2VuZSIpICU+JQojICB0aWJibGUoYXNwZWN0PWZhY3RvcihuYW1lcyguKSxuYW1lcyguKSksZGF0YT0uKSAlPiUKIyAgbXV0YXRlKGRhdGE9bWFwKGRhdGEsYW5ub3RhdGUpKSAlPiUKIyAgdW5uZXN0KGNvbHMgPSAiZGF0YSIpICU+JSBmaWx0ZXIocGFkajxmZHIpICMxOTExMjDkv67mraMgdW5uZXN0KCkgCgpyZV9hbGwgPC0gbWFwKHJlcyxhc190aWJibGUscm93bmFtZXM9ImVuc19nZW5lIikgJT4lCiAgdGliYmxlKGFzcGVjdD1mYWN0b3IobmFtZXMoLiksbmFtZXMoLikpLGRhdGE9LikgJT4lCiAgbXV0YXRlKGRhdGE9bWFwKGRhdGEsYW5ub3RhdGUpKSAlPiUKICB1bm5lc3QoY29scyA9ICJkYXRhIikKCgoKcmUgPC0gcmVfYWxsICU+JSBmaWx0ZXIocGFkajxmZHIpICMxOTExMjDkv67mraMgdW5uZXN0KCkgCgpucm93KHJlX2FsbCAlPiUgZmlsdGVyKGFzcGVjdD09Imdyb3VwMV9DVFhfRGF5NV9IM21tMThLT192c19XVCIpKQpucm93KHJlICU+JSBmaWx0ZXIoYXNwZWN0PT0iZ3JvdXAxX0NUWF9EYXk1X0gzbW0xOEtPX3ZzX1dUIikpCgpmYyA8LSByZSAlPiUgc2VsZWN0KDE6NykgJT4lIGZpbHRlcihhc3BlY3QhPSJJbnRlcmNlcHQiKSAlPiUgc3ByZWFkKGFzcGVjdCxsb2cyRm9sZENoYW5nZSxmaWxsPTApICMgMjAyMDA4MDMg5L+u5q2jCgppbWFwKHJlcyx+ewogIGNhdChwYXN0ZTAoIi0tICIsLnksIiAtLSIpKQogIERFU2VxMjo6c3VtbWFyeSgueCkgIzE5MTEyMOS/ruatoyBERVNlcTI6OnN1bW1hcnkuREVTZXFSZXN1bHRzKC54KQp9KSAlPiUgaW52aXNpYmxlCmBgYAoKIyMjIEdTRUEKCmBgYHtyIEdTRUEsIHdhcm5pbmc9RkFMU0V9Cm1zaWcgPC0gbXNpZ2Ricjo6bXNpZ2RicihzcGVjaWVzKQpmZ3NlYV9tc2lnIDwtIHBhcnRpYWwoZmdzZWE6OmZnc2VhLHdpdGgobXNpZyxzcGxpdChnZW5lX3N5bWJvbCxnc19uYW1lKSkpCmdzY2F0IDwtIG1zaWcgJT4lIHNlbGVjdChnc19uYW1lLGdzX2NhdCxnc19zdWJjYXQpICU+JQogIGRpc3RpbmN0KCkgJT4lIHJlbmFtZShwYXRod2F5PWdzX25hbWUpCgojZ3NlYSA8LSByZSAlPiUgZmlsdGVyKGFzcGVjdCE9IkludGVyY2VwdCIpICU+JSBncm91cF9ieShhc3BlY3QpICU+JQojICBzdW1tYXJpc2UobDJmYz1saXN0KHNldE5hbWVzKGxvZzJGb2xkQ2hhbmdlLGV4dF9nZW5lKSkpICU+JQojICBtdXRhdGUoZ3NlPW1hcChsMmZjLGZnc2VhX21zaWcsbnBlcm09MTAwMDAsbWF4U2l6ZT01MDApKSAlPiUKIyAgc2VsZWN0KC1sMmZjKSAlPiUgdW5uZXN0ICU+JSBhcnJhbmdlKC1ORVMpICU+JSByaWdodF9qb2luKGdzY2F0LC4pICU+JQojICBtdXRhdGUobGVhZGluZ0VkZ2U9bWFwX2NocihsZWFkaW5nRWRnZSxwYXN0ZSxjb2xsYXBzZT0iLCIpKQoKIyBnc2VhIOS/ruato3ZlciBbMjAxOTA2MjFdCiNnc2VhIDwtIHJlICU+JSBmaWx0ZXIoYXNwZWN0IT0iSW50ZXJjZXB0IikgJT4lIGdyb3VwX2J5KGFzcGVjdCkgJT4lCiMgIHN1bW1hcmlzZShsMmZjPWxpc3Qoc2V0TmFtZXMobG9nMkZvbGRDaGFuZ2UsZXh0X2dlbmUpKSkgJT4lCiMgIG11dGF0ZShnc2U9bWFwKGwyZmMsZmdzZWFfbXNpZyxucGVybT0xMDAwMCxtYXhTaXplPTUwMCkpICU+JQojICBzZWxlY3QoLWwyZmMpICU+JSB1bm5lc3QgJT4lIGFycmFuZ2UoLU5FUykgJT4lIHJpZ2h0X2pvaW4oZ3NjYXQsLikgJT4lCiMgIG11dGF0ZShsZWFkaW5nRWRnZT1tYXBfY2hyKGxlYWRpbmdFZGdlLHBhc3RlLGNvbGxhcHNlPSIsIikpICU+JQojICBncm91cF9ieShhc3BlY3QsZ3NfY2F0LGdzX3N1YmNhdCkgJT4lCiMgIG11dGF0ZShwYWRqPXAuYWRqdXN0KHB2YWwsIkJIIikpICU+JSB1bmdyb3VwKCkKCiMgZ3NlYSDkv67mraN2ZXIgWzIwMTkwNjI3XQpnc2VhIDwtIHJlICU+JSBmaWx0ZXIoYXNwZWN0IT0iSW50ZXJjZXB0IikgJT4lIGdyb3VwX2J5KGFzcGVjdCkgJT4lCiAgc3VtbWFyaXNlKGwyZmM9bGlzdChzZXROYW1lcyhsb2cyRm9sZENoYW5nZSxleHRfZ2VuZSkpKSAlPiUKICBmaWx0ZXIobWFwKGwyZmMsbGVuZ3RoKT4xMCkgJT4lCiAgbXV0YXRlKGdzZT1tYXAobDJmYyxmZ3NlYV9tc2lnLG5wZXJtPTEwMDAwLG1heFNpemU9NTAwKSkgJT4lCiAgc2VsZWN0KC1sMmZjKSAlPiUgdW5uZXN0ICU+JSBhcnJhbmdlKC1ORVMpICU+JSByaWdodF9qb2luKGdzY2F0LC4pICU+JQogIG11dGF0ZShsZWFkaW5nRWRnZT1tYXBfY2hyKGxlYWRpbmdFZGdlLHBhc3RlLGNvbGxhcHNlPSIsIikpICU+JQogIGdyb3VwX2J5KGFzcGVjdCxnc19jYXQsZ3Nfc3ViY2F0KSAlPiUKICBtdXRhdGUocGFkaj1wLmFkanVzdChwdmFsLCJCSCIpKSAlPiUgdW5ncm91cCgpCgpgYGAKCmBgYHtyIEhhbGxtYXJrLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpoYWxsbWFyayA8LSBnc2VhICU+JSBmaWx0ZXIoZ3NfY2F0PT0iSCIpICU+JQogIG11dGF0ZShwYXRod2F5PXN1YigiXkhBTExNQVJLXyIsIiIscGF0aHdheSkpICU+JSAKICBncm91cF9ieShhc3BlY3QpICU+JSBuZXN0ICU+JQogIG11dGF0ZShwbHQ9bWFwMihkYXRhLGFzcGVjdCx+CiAgICBnZ3Bsb3QoLngsYWVzKHJlb3JkZXIocGF0aHdheSxORVMpLE5FUyxmaWxsPXBhZGo8MC4xKSkgKwogICAgZ2d0aXRsZSgueSkgKyB4bGFiKCJIYWxsbWFyayBnZW5lIHNldHMiKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfbWluaW1hbCgpICsgY29vcmRfZmxpcCgpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3NjaTo6c2NhbGVfZmlsbF9hYWFzKCkpCiAgKQpwcmludChoYWxsbWFyayRwbHQpCmBgYAoKU2VlIE1TaWdEQiBDb2xsZWN0aW9uczogPGh0dHA6Ly9zb2Z0d2FyZS5icm9hZGluc3RpdHV0ZS5vcmcvZ3NlYS9tc2lnZGIvY29sbGVjdGlvbnMuanNwPgoKIyMjIFdyaXRlLW91dCB0YWJsZXMKCmBgYHtyIHdyaXRlb3V0fQppZihleGlzdHMoImZjIikpICAgcmVhZHI6OndyaXRlX2NzdihmYywiLi8yZ3VuL0JSQjA0MzhyZV9ub3VtaV8xOTA1MTUtSDNtbTE4S09fQ1RYX1MyLURheTBfUzNfbDJmY19mZHIwcDJ2ZXJfZmluMjAwNTIzX2FkZDIwMDgzMS5jc3YiKQppZihleGlzdHMoInJlIikpICAgcmVhZHI6OndyaXRlX2NzdihyZSwiLi8yZ3VuL0JSQjA0MzhyZV9ub3VtaV8xOTA1MTUtSDNtbTE4S09fQ1RYX1MyLURheTBfUzNfcmVzdWx0c19mZHIwcDJ2ZXJfZmluMjAwNTIzX2FkZDIwMDgzMS5jc3YiKQppZihleGlzdHMoInJlX2FsbCIpKSAgIHJlYWRyOjp3cml0ZV9jc3YocmVfYWxsLCIuLzJndW4vQlJCMDQzOHJlX25vdW1pXzE5MDUxNS1IM21tMThLT19DVFhfUzItRGF5MF9TM19yZXN1bHRzYWxsX2ZkcjBwMnZlcl9maW4yMDA1MjNfYWRkMjAwODMxLmNzdiIpCmlmKGV4aXN0cygiZ3NlYSIpKSByZWFkcjo6d3JpdGVfY3N2KGdzZWEsIi4vMmd1bi9CUkIwNDM4cmVfbm91bWlfMTkwNTE1LUgzbW0xOEtPX0NUWF9TMi1EYXkwX1MzX2dzZWFfZmRyMHAydmVyX2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKYGBgCgojIyMgV3JpdGUtb3V0IHRhYmxlcyBIYWxsbWFyawoKYGBge3Igd3JpdGVvdXQgSGFsbG1hcmt9CgpoYWxsbWFya19nc2VhIDwtIGdzZWEgJT4lIGZpbHRlcihnc19jYXQ9PSJIIikgJT4lIG11dGF0ZShwYXRod2F5PXN1YigiXkhBTExNQVJLXyIsIiIscGF0aHdheSkpICU+JSBncm91cF9ieShhc3BlY3QpICU+JSBmaWx0ZXIoYXNwZWN0PT0iZ3JvdXAxX0NUWF9EYXk1X0gzbW0xOEtPX3ZzX1dUIikgCgppZihleGlzdHMoImhhbGxtYXJrX2dzZWEiKSkgICByZWFkcjo6d3JpdGVfY3N2KGhhbGxtYXJrX2dzZWEsIi4vMmd1bi9CUkIwNDM4cmVfbm91bWlfMTkwNTE1LUgzbW0xOEtPX0NUWF9TMi1EYXkwX1MzX2hhbGxtYXJrX2dzZWFfQ1RYX0RheTVfSDNtbTE4S09fdnNfV1RfZmRyMHAydmVyX2ZpbjIwMDUyM19hZGQyMDA4MzEuY3N2IikKYGBgCgojIyMgTUFwbG90CgpgYGB7ciBtYXBsb3R9CiMgU0tNCm1hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXAxX1NLTV9EYXkwX0gzbW0xOEtPX3ZzX1dUICwgeWxpbT1jKC00LDQpLCBtYWluPSJTS00gRGF5MCBIM21tMThLTyB2cyBXVCIpCnByaW50KG1hcGxvdCkKCiMgQ1RYCm1hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXAxX0NUWF9EYXk1X0gzbW0xOEtPX3ZzX1dULCB5bGltPWMoLTQsNCksIG1haW49IkNUWCBEYXk1IEgzbW0xOEtPIHZzIFdUIikKcHJpbnQobWFwbG90KQptYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwMV9DVFhfRGF5MTRfSDNtbTE4S09fdnNfV1QsIHlsaW09YygtNCw0KSwgbWFpbj0iQ1RYIERheTE0IEgzbW0xOEtPIHZzIFdUIikKcHJpbnQobWFwbG90KQoKIyBpbnRhY3QKI21hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXAxX2ludGFjdF9EYXk1X0gzbW0xOEtPX3ZzX1dUICwgeWxpbT1jKC00LDQpLCBtYWluPSJpbnRhY3QgRGF5NSBIM21tMThLTyB2cyBXVCIpCiNwcmludChtYXBsb3QpCiNtYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwMV9pbnRhY3RfRGF5MTRfSDNtbTE4S09fdnNfV1QsIHlsaW09YygtNCw0KSwgbWFpbj0iaW50YWN0IERheTE0IEgzbW0xOEtPIHZzIFdUIikKI3ByaW50KG1hcGxvdCkKCmBgYAoKYGBge3IgY29lZl9kZHN9CgojY29lZihkZHMpCgpjb2VmX2RkcyA8LSBjb2VmKGRkcykgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImVuc19nZW5lIikgJT4lIGFzX3RpYmJsZQoKcmVhZHI6OndyaXRlX2Nzdihjb2VmX2RkcywgIkJSQjA0MzhyZV9IM21tMThLT19tb3VzZV9DVFhfY29lZl9maW4yMDA1MjNfYWRkMjAwODMxLmNzdiIpCgpgYGAKCmBgYHtyIG5vcm0gY291bnQgZGVmIHRhYmxlfQoKU2V0X2N1dG9mZiA8LSAxMC4wCgojIyDlkITmmYLliLvjga7lubPlnYfjgpLoqIjnrpfjgZfjgIFub3JtYWxpemVkIGNvdW50ID4gMTAg44KS6LaF44GI44KL44KC44Gu44KS5oq95Ye644GZ44KL44CCCgojLS0tLS0gU0tN44GoQ1RY44Gu44G/5Y+W44KK5Ye644GZIC0tLSMgMjAxOTEyMDUKbm9ybV9wbG90bGlzdF9hbGwgPC0gbm9ybWFsaXplZGNvdW50ICU+JSBnYXRoZXIoInNhbXBsZSIsICJub3JtYWxpemVkIiwtKGVuc19nZW5lKSkgJT4lIGlubmVyX2pvaW4oZGVmLCBieSA9ICJzYW1wbGUiKQpub3JtX3Bsb3RsaXN0X2FsbCA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgZmlsdGVyKGludGFjdF9DVFg9PSJDVFgifGludGFjdF9DVFg9PSJTS00iKSAlPiUgbXV0YXRlKFdUX0tPPWZhY3RvcihXVF9LTywgYygiSDNtbTE4S08iLCJXVCIpKSkgJT4lIG11dGF0ZShEYXk9ZmFjdG9yKERheSwgYygiRGF5MCIsIkRheTUiLCJEYXkxNCIpKSkgJT4lIG11dGF0ZShpbnRhY3RfQ1RYPWZhY3RvcihpbnRhY3RfQ1RYLCBjKCJDVFgiLCJTS00iKSkpCgojbm90bV9wbG90bGlzdF9jdXRvZmYgPC0gbm9ybV9wbG90bGlzdF9hbGwgJT4lIGFubm90YXRlKCkgJT4lIGdyb3VwX2J5KGVuc19nZW5lLCBleHRfZ2VuZSwgRGF5LCBpbnRhY3RfQ1RYKSAlPiUgc3VtbWFyaXNlKGdyb3VwTWVhbj1tZWFuKG5vcm1hbGl6ZWQpKSAgJT4lIHVuZ3JvdXAoKSAlPiUgZHBseXI6OnNlbGVjdChlbnNfZ2VuZSwgZXh0X2dlbmUpICU+JSB1bmlxdWUoKQoKCm5vdG1fcGxvdGxpc3RfYmVmb3JlY3V0b2ZmIDwtIG5vcm1fcGxvdGxpc3RfYWxsICU+JSBhbm5vdGF0ZSgpICU+JSBncm91cF9ieShlbnNfZ2VuZSwgZXh0X2dlbmUsIERheSwgaW50YWN0X0NUWCkgJT4lIHN1bW1hcmlzZShncm91cE1lYW49bWVhbihub3JtYWxpemVkKSkKCm5vdG1fcGxvdGxpc3RfY3V0b2ZmIDwtIG5vdG1fcGxvdGxpc3RfYmVmb3JlY3V0b2ZmICU+JSBmaWx0ZXIoZ3JvdXBNZWFuID4gU2V0X2N1dG9mZikgJT4lIHVuZ3JvdXAoKSAlPiUgZHBseXI6OnNlbGVjdChlbnNfZ2VuZSwgZXh0X2dlbmUpICU+JSB1bmlxdWUoKQoKbnJvdyhub3RtX3Bsb3RsaXN0X2JlZm9yZWN1dG9mZiAlPiUgdW5ncm91cCgpICU+JSBkcGx5cjo6c2VsZWN0KGVuc19nZW5lLCBleHRfZ2VuZSkgJT4lIHVuaXF1ZSgpKSAj44GT44Gu5YCk44KSTUFwbG9044GueOi7uOOBq+S9v+eUqApucm93KG5vdG1fcGxvdGxpc3RfY3V0b2ZmKSAj6Kej5p6Q5a++6LGh44KS57We44KL44CAKOW+jOOBruWFqOS9k+OBruOCr+ODqeOCueOCv+ODquODs+OCsOOBq+S9v+eUqCkKCgpgYGAKYGBge3Igbm9ybV9wbG90bGlzdF9hbGx9Cgpub3JtX3Bsb3RsaXN0X2FsbCAlPiUgcmVhZHI6OndyaXRlX2NzdigiTm9ybV9kZWZ0YWJsZS5jc3YiKQpub3RtX3Bsb3RsaXN0X2JlZm9yZWN1dG9mZiAlPiUgcmVhZHI6OndyaXRlX2NzdigiTm9ybV9ncm91cE1lYW4uY3N2IikKbm90bV9wbG90bGlzdF9jdXRvZmYgICU+JSByZWFkcjo6d3JpdGVfY3N2KCJOb3JtX2dyb3VwTWVhbl9jdXRvZmYxMC5jc3YiKQoKCm5yb3cobm90bV9wbG90bGlzdF9iZWZvcmVjdXRvZmYpCm5yb3cobm90bV9wbG90bGlzdF9jdXRvZmYpCgpgYGAKCiMjIyBNQXBsb3QgKGJ5IGhhbmQpCgpBU0NzX2xpc3QgZnJvbSAiSGlzdG9uZSBIMy4zIHN1Yi12YXJpYW50IEgzbW03IGlzIHJlcXVpcmVkIGZvciBub3JtYWwgc2tlbGV0YWwgbXVzY2xlIHJlZ2VuZXJhdGlvbiIsIEhhcmFkYSwgTWFlaGFyYSBldCBhbC4KCmBgYHtyIHdyaXRlb3V0IG1hcGxvdCBieSBoYW5kLCBmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTR9CiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tICMjIwoKI01HSUdPIDwtIHJlYWRyOjpyZWFkX3RzdigiL2hvbWUvZ3Vlc3RBL283MDU3OGEvYWt1d2FrYWRvL2t1d2FrYWRvL1JlZmVyZW5jZV9maWxlcy9Nb3VzZV9HZW5vbWVfSW5mb3JtYXRpY3NfbWdpX0dPL01HSV9Bbm5vdGF0aW9uc18yMDIwMDgwNmRvd25sb2FkL0dPX3Rlcm1fc3VtbWFyeV8yMDIwMDgwNV8yMjA3MDBfX0dPMDAzNTkxNF9za2VsZXRhbF9tdXNjbGVfY2VsbF9kaWZmZXJlbnRpYXRpb24udHh0Iixjb2xfbmFtZXMgPSBjKCJNR0kiLCJleHRfZ2VuZSIpKQoKI01HSVNDX3RhYmxlR08gPC0gcmVhZHI6OnJlYWRfdHN2KCIvaG9tZS9ndWVzdEEvbzcwNTc4YS9ha3V3YWthZG8va3V3YWthZG8vQlJCU2VxL0gzbW0xOEtPX2FuZF9IM3AzS09fMDQzOC9SX3NlcnZlcl9fbW91c2VfSDNtbTE4S09fQ1RYX18xOTA5MjQtL0ZpbmFsX0xhc3RfUnNlcnZlcl8yMDA1MjNfYWRkMjAwODMxL3RhYmxlX0dPdGVybV9TQ3MudHh0Iixjb2xfbmFtZXMgPSBjKCJmaWxlIikpCgoKI01HSVNDIDwtIE1HSVNDX3RhYmxlR08kZmlsZSAlPiUgdW5pcXVlICU+JSB0aWJibGUoZmlsZT0uKSAlPiUgCiMgIGRwbHlyOjptdXRhdGUoZGF0YT1tYXAoZmlsZSxyZWFkcjo6cmVhZF90c3YscHJvZ3Jlc3M9RkFMU0UpKSAlPiUKIyAgdW5uZXN0KGNvbHMgPSBjKGRhdGEpKQoKI01HSVNDX2dlbmUgPC0gTUdJU0MgJT4lIGRwbHlyOjpzZWxlY3QoU3ltYm9sLGBBbm5vdGF0ZWQgVGVybWApICU+JSBncm91cF9ieShTeW1ib2wpICU+JSBzdW1tYXJpc2UoY291bnQ9bigpLCAgYEFubm90YXRlZCBUZXJtYD1wYXN0ZShgQW5ub3RhdGVkIFRlcm1gLGNvbGxhcHNlID0gIiwgIikpICU+JSB1bmlxdWUoKSAgICU+JSBtdXRhdGUobGlzdDE9Y2FzZV93aGVuKHN0cl9kZXRlY3QoYEFubm90YXRlZCBUZXJtYCwgIm5lZ2F0aXZlIil+Im5lZ2F0aXZlIixzdHJfZGV0ZWN0KGBBbm5vdGF0ZWQgVGVybWAsICJwb3NpdGl2ZSIpfiJwb3NpdGl2ZSIsc3RyX2RldGVjdChgQW5ub3RhdGVkIFRlcm1gLCAic2F0ZWxsaXRlIGNlbGwgYWN0aXZhdGlvbiIpfiJwb3NpdGl2ZSIsVFJVRSB+ICJPdGhlciIpKSAlPiUgcmVuYW1lKGV4dF9nZW5lPVN5bWJvbCkKCiMlPiUgZmlsdGVyKGxpc3QxPT0icG9zaXRpdmUiKQoKClNLTUgzbW03IDwtIHJlYWRyOjpyZWFkX3RzdigiL2hvbWUvZ3Vlc3RBL243MDI3NWIvd29yay90aXNzdWVjaGlsL3Rpc3V1ZXMvc2ttdXNjbGVfbWFya2Vycy50eHQiKSAjIDQz5YCLCgojU0NzX3N1cGxpc3QgPC0gYygiQWN2cjJhIiwiQ2F2MSIsIkNkMzQiLCJDZGgxNSIsIkN4Y2wxMiIsIkN4Y3I0IiwiRGVzIiwiRWdmciIsIkZveGsxIiwiSG94YzEwIiwiSXRnYTQiLCJJdGdhNyIsIkl0Z2IxIiwiTGJ4MSIsIk1ldCIsIk15b2QxIiwiTmNhbTEiLCJOZ2ZyIiwiUGF4NyIsIlNkYzMiLCJTZGM0IiwiU294OSIsIlZjYW0xIiwiTWUxIiwiVnBzNzIiLCJUY2VhbDUiLCJIbnJucGEyYjEiLCIwNjEwMDEyRzAzUmlrIiwiU2drMSIsIkhkYWM1IiwiWmNyYjEiLCJHcGMxIiwiQ2JmYiIsIkdweDEiLCJXZHIyNiIsIk1mZiIsIkNkNjMiLCJDb2wxYTEiLCJUc3BhbjkiLCJBdHA1YiIsIlRubmMyIiwiTmR1ZmMyIiwiTmZpYiIsIkhiYi1icyIsIlNmMSIsIlRuczEiLCJIcmMiLCJTbW94IiwiRWNoMSIsIkFjdGMxIiwiS3J0Y2FwMiIsIlNiazIiKSAjIDUy5YCLCiMg44GL44G244KK44Gv77yS77yT5YCLCgoKIyMjIyMjIyMjIyMjCiMjIEZpZzHjgojjgooKQVFTQ19saXN0IDwtIGMoIkN4Y2wxMiIsIkNhdjEiLCJFZ2ZyIiwiQ2QzNCIsIlZjYW0xIiwiTWVnZjEwIiwiTXN4MSIsIlMxcHIxIiwiTmNhbTEiLCJTb3g5IikKI2UyZyAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgQVFTQ19saXN0KQpBU0NfbGlzdCA8LSBjKCJTZGMzIiwiQ3hjcjQiLCJOZXMiLCJOZG4iLCJNeWY1IiwiSXRnYjEiLCJBZGdyZzMiLCJNeW9kMSIsIlNveDgiLCJFcmJiMiIsIk5ybjEiKSAjIlNkYzMiLCJDeGNyNCIsIk5lcyIsIk5kbiIsIk15ZjUiLAojZTJnICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBBU0NfbGlzdCkKUVNDX2xpc3QgPC0gYygiUGF4NyIsIlNkYzQiLCJCZG5mIiwiTmdmciIsIkNhbGNyIiwiQ2RoMTUiLCJQYXgzIiwiQ2FkbTEiKSAjQUREICJCZG5mIiwiQ2FsY3IiLCJQYXgzIiwiQ2FkbTEiIE9LIHBsdXMgMgojZTJnICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBRU0NfbGlzdCkKTUZfbGlzdCA8LSBjKCJBY3ZyMmEiLCJEZXMiLCJGb3hrMSIsIkhveGMxMCIsIkl0Z2E0IiwiSXRnYTciLCJMYngxIiwiTWV0IiwiRXJiYjMiLCJFcmJiNCIsIk1zdG4iKSAjQUREICJFcmJiNCIiRXJiYjMiIk1zdG4iIE9LIHBsdXMgOAojZTJnICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBNRl9saXN0KQojIyMjIyMjIyMjIyMKCm1hcmtlclNDcyA8LSBlMmcgJT4lIGZpbHRlcihlbnNfZ2VuZSAlaW4lIFNLTUgzbW03JGdlbmVfaWQpICAlPiUgbXV0YXRlKGNsdXM9Y2FzZV93aGVuKGV4dF9nZW5lICVpbiUgQVFTQ19saXN0IH4iQVNDIixleHRfZ2VuZSAlaW4lIEFTQ19saXN0IH4iQVNDIixleHRfZ2VuZSAlaW4lIFFTQ19saXN0IH4iUVNDIixleHRfZ2VuZSAlaW4lIE1GX2xpc3QgfiJNRiIsVFJVRSB+ICJvdGhlciIpKSAlPiUgbXV0YXRlKExpc3Q9ZmFjdG9yKGNsdXMsIGMoIkFTQyIsIlFTQyIsIk1GIiwib3RoZXIiKSkpICU+JSBmaWx0ZXIoY2x1cyAlaW4lIGMoIkFTQyIsIlFTQyIsIk1GIikpCgojbWFya2VyU0NzIDwtIGUyZyAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgU0tNSDNtbTckZ2VuZV9pZCkgICU+JSBtdXRhdGUoY2x1cz1jYXNlX3doZW4oZXh0X2dlbmUgJWluJSBBUVNDX2xpc3QgfiJBU0NfUVNDIixleHRfZ2VuZSAlaW4lIFFTQ19saXN0IH4iUVNDIixleHRfZ2VuZSAlaW4lIEFTQ19saXN0IH4iQVNDIixleHRfZ2VuZSAlaW4lIE1GX2xpc3QgfiJNRiIsVFJVRSB+ICJvdGhlciIpKSAlPiUgbXV0YXRlKExpc3Q9ZmFjdG9yKGNsdXMsIGMoIkFTQyIsIlFTQyIsIkFTQ19RU0MiLCJNRiIsIm90aGVyIikpKSAlPiUgZmlsdGVyKGNsdXMgJWluJSBjKCJBU0MiLCJRU0MiLCJBU0NfUVNDIikpCgojJT4lIG11dGF0ZShjbHVzPWNhc2Vfd2hlbihMaXN0ICVpbiUgYygiQVNDIiwiUVNDIiwiQVNDX1FTQyIpIH4iU0MiLExpc3QgJWluJSBjKCJNRiIpIH4iTUYiLExpc3QgJWluJSBjKCJTS00iKSB+IlNLTSIsVFJVRSB+ICIiKSkKCm1hcmtlclNDcyAlPiUgZ3JvdXBfYnkoY2x1cykgJT4lIHN1bW1hcmlzZShjb3VudD1uKCksICBnZW5lPXBhc3RlKGV4dF9nZW5lLGNvbGxhcHNlID0gIiwgIikpCgptYXJrZXJTQ3MgJT4lIHJlYWRyOjp3cml0ZV9jc3YoIi4vU0NzbWFrZXJsaXN0X2luTUFwbG90LmNzdiIpCgojbWFya2VyX01BIDwtIG1hcmtlclNDcyAlPiUgZmlsdGVyKExpc3QgJWluJSBjKCJBU0MiLCJRU0MiLCJBU0NfUVNDIikpCiNtYXJrZXJfTUEgPC0gZTJnICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBNR0lHTyRleHRfZ2VuZSkKI21hcmtlcl9NQSA8LSBlMmcgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIkNhcG4zIiwiU294MTUiKSkKI21hcmtlcl9NQSA8LSBlMmcgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIFNDc19zdXBsaXN0KQoKCiNtYXJrZXJfTUEgPC0gZTJnICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBNR0lTQ19nZW5lJGV4dF9nZW5lKSAlPiUgbGVmdF9qb2luKE1HSVNDX2dlbmUpCm1hcmtlcl9NQSA8LSBlMmcgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIG1hcmtlclNDcyRleHRfZ2VuZSkgJT4lIGxlZnRfam9pbihtYXJrZXJTQ3MpCgoKYGBgCgpgYGB7ciBtYXBsb3QgZHJhdywgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDh9CgojZl9TQ3MgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgU0NzX2xpc3QpICPkvZzlm7PnlKgKI2ZjICU+JSBmX1NDcwoKI2ZfTUYgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgTUZfbGlzdCkgI+S9nOWbs+eUqAojZmMgJT4lIGZfTUYKCiNyZV9hbGxfcGxvdCA8LSByZV9hbGwgJT4lIG11dGF0ZShjbHVzdGVyPWNhc2Vfd2hlbihleHRfZ2VuZSAlaW4lIFNDc19saXN0fiJTQyIsZXh0X2dlbmUgJWluJSBNRl9saXN0fiJNRiIsVFJVRSB+ICJGQUxTRSIpKSAlPiUgbXV0YXRlKGxhYmVsX3RleHQ9Y2FzZV93aGVuKGV4dF9nZW5lICVpbiUgQVNDc19saXN0IH4gZXh0X2dlbmUsVFJVRSB+ICIiKSkgICU+JSBtdXRhdGUoY2x1c3Rlcj1mYWN0b3IoY2x1c3RlciwgYygiU0MiLCJNRiIsIkZBTFNFIikpKQoKI2ZfbWFya2VyTUFfaW4gPC0gZnVuY3Rpb24oeCkgeCAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgbWFya2VyX01BJGVuc19nZW5lKQoKI2ZfbWFya2VyTUFfaW4gPC0gZnVuY3Rpb24oeCkgeCAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgbWFya2VyX01BJGVuc19nZW5lKSAlPiUgbGVmdF9qb2luKG1hcmtlcl9NQSkKI2ZfbWFya2VyTUFfaW5fQVNDcyA8LSBmdW5jdGlvbih4KSB4ICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBtYXJrZXJfTUEkZW5zX2dlbmUpICU+JSBsZWZ0X2pvaW4obWFya2VyX01BKSAlPiUgZmlsdGVyKGNsdXN0ZXIgJWluJSBjKCJBU0MiKSkKI2ZfbWFya2VyTUFfb3V0IDwtIGZ1bmN0aW9uKHgpIHggJT4lIGZpbHRlcighZW5zX2dlbmUgJWluJSBtYXJrZXJfTUEkZW5zX2dlbmUpCgoKZl9tYXJrZXJNQV9pbiA8LSBmdW5jdGlvbih4KSB4ICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBtYXJrZXJfTUEkZW5zX2dlbmUpCmZfbWFya2VyTUFfaW5fQVNDcyA8LSBmdW5jdGlvbih4KSB4ICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBtYXJrZXJfTUEkZW5zX2dlbmUpICU+JSBsZWZ0X2pvaW4obWFya2VyX01BKSAlPiUgZmlsdGVyKGNsdXN0ZXIgJWluJSBjKCJBU0MiKSkKZl9tYXJrZXJNQV9vdXQgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZmlsdGVyKCFlbnNfZ2VuZSAlaW4lIG1hcmtlcl9NQSRlbnNfZ2VuZSkKCiNyZV9hbGxfcGxvdCA8LSByZV9hbGwgJT4lIG11dGF0ZShjbHVzdGVyPWNhc2Vfd2hlbihlbnNfZ2VuZSAlaW4lIG1hcmtlcl9NQSRlbnNfZ2VuZX4ibWFya2VyIixUUlVFIH4gIkZBTFNFIikpICU+JSBtdXRhdGUobGFiZWxfdGV4dD1jYXNlX3doZW4oZXh0X2dlbmUgJWluJSBtYXJrZXJfTUEkZXh0X2dlbmUgfiBleHRfZ2VuZSxUUlVFIH4gIiIpKSU+JSBtdXRhdGUoY2x1c3Rlcj1mYWN0b3IoY2x1c3RlciwgYygibWFya2VyIiwiRkFMU0UiKSkpCgoKI3JlX2FsbF9wbG90IDwtIHJlX2FsbCAlPiUgbGVmdF9qb2luKG1hcmtlcl9NQSkgJT4lIG11dGF0ZShjbHVzdGVyPWNhc2Vfd2hlbighaXMubmEobGlzdDEpfmxpc3QxLFRSVUUgfiAiRkFMU0UiKSkgJT4lIG11dGF0ZShsYWJlbF90ZXh0PWNhc2Vfd2hlbihleHRfZ2VuZSAlaW4lIG1hcmtlcl9NQSRleHRfZ2VuZSB+IGV4dF9nZW5lLFRSVUUgfiAiIikpICU+JSAgbXV0YXRlKGNsdXN0ZXI9ZmFjdG9yKGNsdXN0ZXIsIGMoInBvc2l0aXZlIiwiT3RoZXIiLCJuZWdhdGl2ZSIpKSkKCnJlX2FsbF9wbG90IDwtIHJlX2FsbCAlPiUgbGVmdF9qb2luKG1hcmtlcl9NQSkgJT4lIG11dGF0ZShjbHVzdGVyPWNhc2Vfd2hlbighaXMubmEoY2x1cyl+Y2x1cyxUUlVFIH4gIkZBTFNFIikpICAlPiUgbXV0YXRlKGxhYmVsX3RleHQ9Y2FzZV93aGVuKGV4dF9nZW5lICVpbiUgQVFTQ19saXN0IH4gZXh0X2dlbmUsIGV4dF9nZW5lICVpbiUgQVNDX2xpc3QgfiBleHRfZ2VuZSxleHRfZ2VuZSAlaW4lIFFTQ19saXN0IH5leHRfZ2VuZSwgVFJVRSB+ICIiKSkgICU+JSBtdXRhdGUoY2x1c3Rlcj1mYWN0b3IoY2x1c3RlciwgYygiQVNDIiwiUVNDIiwiTUYiLCJGQUxTRSIpKSkKCiMlPiUgIG11dGF0ZShjbHVzdGVyPWZhY3RvcihjbHVzdGVyLCBjKCJTQyIsIk1GIiwiU0tNIikpKQoKCgojIyMjCnJlX3NlbGVjdF9wbG90IDwtIHJlX2FsbF9wbG90ICU+JSBmaWx0ZXIoYXNwZWN0IT0iSW50ZXJjZXB0IikgJT4lIG11dGF0ZShEYXk9Y2FzZV93aGVuKGFzcGVjdD09Imdyb3VwMV9TS01fRGF5MF9IM21tMThLT192c19XVCJ+IkRheTAiLGFzcGVjdD09Imdyb3VwMV9DVFhfRGF5NV9IM21tMThLT192c19XVCJ+IkRheTUiLGFzcGVjdD09Imdyb3VwMV9DVFhfRGF5MTRfSDNtbTE4S09fdnNfV1QifiJEYXkxNCIsVFJVRSB+ICJGQUxTRSIpKSAgJT4lIGxlZnRfam9pbihub3RtX3Bsb3RsaXN0X2JlZm9yZWN1dG9mZikgICU+JSBtdXRhdGUoRGF5PWZhY3RvcihEYXksIGMoIkRheTAiLCJEYXk1IiwiRGF5MTQiKSkpIAoKRGF5bWVhbiA8LSByZV9zZWxlY3RfcGxvdCAlPiUgZ3JvdXBfYnkoRGF5KSAlPiUgc3VtbWFyaXNlKERheU1lYW49bWVhbihncm91cE1lYW4pKQpNZWFuX2NvbG9yIDwtICIjQjg4NjBCIgoKRGF5bWVhbgoKQWxsZ2VuZV9udW0gPC0gcmVfc2VsZWN0X3Bsb3QgJT4lIGRwbHlyOjpzZWxlY3QoZW5zX2dlbmUpICU+JSB1bmlxdWUoKSAlPiUgbnJvdygpCm1hcmtlcl9udW0gPC0gcmVfc2VsZWN0X3Bsb3QgJT4lIGZfbWFya2VyTUFfaW4gJT4lIGRwbHlyOjpzZWxlY3QoZW5zX2dlbmUpICU+JSB1bmlxdWUoKSAlPiUgbnJvdygpCm1hcmtlcl9udW1fc3VtIDwtIHJlX3NlbGVjdF9wbG90ICU+JSBmX21hcmtlck1BX2luICU+JSBkcGx5cjo6c2VsZWN0KGVuc19nZW5lLGV4dF9nZW5lLGNsdXN0ZXIpICU+JSB1bmlxdWUoKSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShjb3VudD1uKCkpCgoKZ2dnZ2xhYmVsIDwtIHBhc3RlKEFsbGdlbmVfbnVtLCAiZ2VuZXMsIiwgbWFya2VyX251bSwibWFya2VyIGdlbmVzICgiLG1hcmtlcl9udW1fc3VtJGNsdXN0ZXJbMV0sbWFya2VyX251bV9zdW0kY291bnRbMV0sbWFya2VyX251bV9zdW0kY2x1c3RlclsyXSxtYXJrZXJfbnVtX3N1bSRjb3VudFsyXSxtYXJrZXJfbnVtX3N1bSRjbHVzdGVyWzNdLG1hcmtlcl9udW1fc3VtJGNvdW50WzNdLCIpIixzZXA9IiAiKQoKCgpyZV9zZWxlY3RfcGxvdCAlPiUgZl9tYXJrZXJNQV9pbiAlPiUgZHBseXI6OnNlbGVjdChlbnNfZ2VuZSxleHRfZ2VuZSxjbHVzdGVyKSAlPiUgdW5pcXVlKCkgJT4lIGFycmFuZ2UoY2x1c3RlcikKcmVfc2VsZWN0X3Bsb3QgJT4lIGZfbWFya2VyTUFfaW4gJT4lIGRwbHlyOjpzZWxlY3QoZW5zX2dlbmUsZXh0X2dlbmUsY2x1c3RlcikgJT4lIHVuaXF1ZSgpICU+JSBhcnJhbmdlKGNsdXN0ZXIpICU+JSByZWFkcjo6d3JpdGVfY3N2KCIuL0RheWFsbF9NQXBsb3RfU0tNbGlzdC5jc3YiKQoKcmVfc2VsZWN0X3Bsb3QgJT4lIHJlYWRyOjp3cml0ZV9jc3YoIi4vRGF5YWxsX01BcGxvdGRhdGEuY3N2IikKCiMjIyMjIyMjCgpnZ21hcGxvdCA8LSByZV9zZWxlY3RfcGxvdCAgJT4lICBnZ3Bsb3QoYWVzKGdyb3VwTWVhbixsb2cyRm9sZENoYW5nZSxjb2xvcj1jbHVzdGVyKSkrZ2VvbV9wb2ludChzaXplPTAuMSwgYWxwaGEgPSAwLjUsZGF0YT1mX21hcmtlck1BX291dCxjb2xvcj0iI2JkYmRiZCIpICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsc2xvcGU9MCxjb2xvdXI9ImJsYWNrIixzaXplPTAuMikgICtnZW9tX3BvaW50KGFlcyhncm91cE1lYW4sbG9nMkZvbGRDaGFuZ2UsY29sb3I9Y2x1c3Rlciksc2l6ZT0wLjMsIGRhdGE9Zl9tYXJrZXJNQV9pbikgKyBzY2FsZV94X2xvZzEwKCkgKyB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsgZ2d0aXRsZShnZ2dnbGFiZWwpICsgeWxpbSgtNS4wLCA1LjApICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNmZjAwMDAiLCIjMDAwMGZmIiwiIzAwMDAwMCIpKSArIGZhY2V0X3dyYXAofkRheSxuY29sPTEpICsgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSxheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsdmp1c3Q9MS4wKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0Iiwgc3RyaXAudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSksc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSx0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgpKQoKCiMscGFuZWwuZ3JpZD1lbGVtZW50X2JsYW5rKCkKCmdnc2F2ZShmaWxlPSJEYXlBbGxfTUFwbG90LnBkZiIsIHBsb3QgPSBnZ21hcGxvdCwgd2lkdGggPSA3LCBoZWlnaHQgPSA4LCBkcGkgPSAxMjApCnBsb3QoZ2dtYXBsb3QpCgojIyMjIyMjIwoKCmdnbWFwbG90IDwtIHJlX3NlbGVjdF9wbG90ICAlPiUgIGdncGxvdChhZXMoZ3JvdXBNZWFuLGxvZzJGb2xkQ2hhbmdlLGNvbG9yPWNsdXN0ZXIpKStnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYSA9IDAuNSxkYXRhPWZfbWFya2VyTUFfb3V0LGNvbG9yPSIjYmRiZGJkIikgKyBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0wLGNvbG91cj0iYmxhY2siLHNpemU9MC4yKSAgKyBnZW9tX3ZsaW5lKGRhdGEgPSBEYXltZWFuLCBhZXMoeGludGVyY2VwdD1EYXlNZWFuKSxjb2xvdXI9TWVhbl9jb2xvcixzaXplPTAuMixsaW5ldHlwZT0iZGFzaGVkIikgK2dlb21fcG9pbnQoYWVzKGdyb3VwTWVhbixsb2cyRm9sZENoYW5nZSxjb2xvcj1jbHVzdGVyKSxzaXplPTAuMywgZGF0YT1mX21hcmtlck1BX2luKSArIHNjYWxlX3hfbG9nMTAoKSArIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyBnZ3RpdGxlKGdnZ2dsYWJlbCkgKyB5bGltKC01LjAsIDUuMCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI2ZmMDAwMCIsIiMwMDAwZmYiLCIjMDAwMDAwIikpICsgZmFjZXRfd3JhcCh+RGF5LG5jb2w9MSkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTUpLGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSx2anVzdD0xLjApLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSxzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCkpCgpnZ3NhdmUoZmlsZT0iRGF5QWxsX01BcGxvdF9NZWFuLnBkZiIsIHBsb3QgPSBnZ21hcGxvdCwgd2lkdGggPSA3LCBoZWlnaHQgPSA4LCBkcGkgPSAxMjApCnBsb3QoZ2dtYXBsb3QpCgoKYGBgCgoKYGBge3IgbGxsbGxsIGFsbCwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDh9CgpkZW5zaXR5X2NvbG9yX2xvdyA8LSAiI0ZGRkZGRiIKZGVuc2l0eV9jb2xvcl9oaWdoIDwtICJibHVlIgpkZW5zaXR5X2NvbG9yX2hpZ2ggPC0gIiNGRkQ0MDAiCgoKCiNkZW5zaXR5X2NvbG9yX2hpZ2ggPC0gImdyYXkiCgojREFBNTIwCgojTWVhbl9ncm91cG1lYW4gPC0gbWVhbihyZV9zZWxlY3RfcGxvdCRncm91cE1lYW4pCiNNZWFuX2xvZzJGQyA8LSBtZWFuKHJlX3NlbGVjdF9wbG90JGxvZzJGb2xkQ2hhbmdlKQoKZmZmZiA8LSByZV9zZWxlY3RfcGxvdCAgJT4lIG11dGF0ZShEYXk9ZmFjdG9yKERheSwgYygiRGF5MCIsIkRheTUiLCJEYXkxNCIpKSkgICU+JSAgZ2dwbG90KGFlcyh4PWdyb3VwTWVhbix5PWxvZzJGb2xkQ2hhbmdlKSkgICsgc3RhdF9kZW5zaXR5MmQoYWVzKGZpbGw9Li5kZW5zaXR5Li4pLCBnZW9tID0gInJhc3RlciIsY29udG91ciA9IEZBTFNFKSsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSBkZW5zaXR5X2NvbG9yX2xvdywgaGlnaCA9IGRlbnNpdHlfY29sb3JfaGlnaCkgKyBzY2FsZV94X2xvZzEwKGJyZWFrcz0xMF4oLTE6NCksbGltaXRzPSBjKDAuMSwgMTAwMDApKSAgKyBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0wLGNvbG91cj0iIzAwMDAwMCIsc2l6ZT0wLjIpICArIGdlb21fdmxpbmUoZGF0YSA9IERheW1lYW4sIGFlcyh4aW50ZXJjZXB0PURheU1lYW4pLGNvbG91cj1NZWFuX2NvbG9yLHNpemU9MC4yLGxpbmV0eXBlPSJkYXNoZWQiKSArIGdlb21fZGVuc2l0eTJkKGNvbG9yPSIjZmYwMDAwIixkYXRhPWZfbWFya2VyTUFfaW5fQVNDcyxzaXplPTAuMSwgYmlucz03KSArZ2VvbV9wb2ludChhZXMoZ3JvdXBNZWFuLGxvZzJGb2xkQ2hhbmdlLGNvbG9yPWNsdXN0ZXIpLHNpemU9MS4wLCBkYXRhPWZfbWFya2VyTUFfaW5fQVNDcykgKyB5bGltKC0xLDEpICsgZmFjZXRfd3JhcCh+RGF5LCBuY29sID0gMSkgKyB0aGVtZV9idygpICsgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSxheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsdmp1c3Q9MS4wKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0Iiwgc3RyaXAudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSksc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSx0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgpLHBhbmVsLmdyaWQ9ZWxlbWVudF9ibGFuaygpKSAgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI2ZmMDAwMCIsIiMwMDAwZmYiLCIjMDAwMDAwIikpCgoKZmZmZgpnZ3NhdmUoZmlsZT0iRGF5QWxsX2RlbnNpdHlNQXBsb3RfQVNDLnBkZiIsIHBsb3QgPSBmZmZmLCB3aWR0aCA9IDQsIGhlaWdodCA9IDgsIGRwaSA9IDEyMCkKCmZmZmYgPC0gcmVfc2VsZWN0X3Bsb3QgICU+JSBtdXRhdGUoRGF5PWZhY3RvcihEYXksIGMoIkRheTAiLCJEYXk1IiwiRGF5MTQiKSkpICAlPiUgIGdncGxvdChhZXMoeD1ncm91cE1lYW4seT1sb2cyRm9sZENoYW5nZSkpICArIHN0YXRfZGVuc2l0eTJkKGFlcyhmaWxsPS4uZGVuc2l0eS4uKSwgZ2VvbSA9ICJyYXN0ZXIiLGNvbnRvdXIgPSBGQUxTRSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gZGVuc2l0eV9jb2xvcl9sb3csIGhpZ2ggPSBkZW5zaXR5X2NvbG9yX2hpZ2gpICsgc2NhbGVfeF9sb2cxMChicmVha3M9MTBeKC0xOjQpLGxpbWl0cz0gYygwLjEsIDEwMDAwKSkgICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsc2xvcGU9MCxjb2xvdXI9IiMwMDAwMDAiLHNpemU9MC4yKSAgKyBnZW9tX3ZsaW5lKGRhdGEgPSBEYXltZWFuLCBhZXMoeGludGVyY2VwdD1EYXlNZWFuKSxjb2xvdXI9TWVhbl9jb2xvcixzaXplPTAuMixsaW5ldHlwZT0iZGFzaGVkIikgKyBnZW9tX2RlbnNpdHkyZChjb2xvcj0iI2ZmMDAwMCIsZGF0YT1mX21hcmtlck1BX2luX0FTQ3Msc2l6ZT0wLjEsIGJpbnM9NykgK2dlb21fcG9pbnQoYWVzKGdyb3VwTWVhbixsb2cyRm9sZENoYW5nZSxjb2xvcj1jbHVzdGVyKSxzaXplPTEuMCwgZGF0YT1mX21hcmtlck1BX2luKSArIHlsaW0oLTEsMSkgKyBmYWNldF93cmFwKH5EYXksIG5jb2wgPSAxKSArIHRoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTUpLGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSx2anVzdD0xLjApLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSxzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCkscGFuZWwuZ3JpZD1lbGVtZW50X2JsYW5rKCkpICArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmYwMDAwIiwiIzAwMDBmZiIsIiMwMDAwMDAiKSkKCmZmZmYKZ2dzYXZlKGZpbGU9IkRheUFsbF9kZW5zaXR5TUFwbG90X1NDcy5wZGYiLCBwbG90ID0gZmZmZiwgd2lkdGggPSA0LCBoZWlnaHQgPSA4LCBkcGkgPSAxMjApCgoKYGBgCgpgYGB7ciBkZW5zaXR5IEFTQ3MgdnMgYWxsfQoKZmZmZiA8LSByZV9zZWxlY3RfcGxvdCAlPiUgbXV0YXRlKERheT1mYWN0b3IoRGF5LCBjKCJEYXkwIiwiRGF5NSIsIkRheTE0IikpKSAgJT4lICBnZ3Bsb3QoYWVzKHg9Z3JvdXBNZWFuLHk9bG9nMkZvbGRDaGFuZ2UpKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gZGVuc2l0eV9jb2xvcl9sb3csIGhpZ2ggPSBkZW5zaXR5X2NvbG9yX2hpZ2gpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiMwMDAwMDAiLCBoaWdoID0gIiNmZjAwMDAiKSArIHN0YXRfZGVuc2l0eTJkKGFlcyhmaWxsPS4uZGVuc2l0eS4uKSwgZ2VvbSA9ICJyYXN0ZXIiLGNvbnRvdXIgPSBGQUxTRSkgKyBnZW9tX2RlbnNpdHkyZChhZXMoY29sb3I9Li5sZXZlbC4uKSxkYXRhPWZfbWFya2VyTUFfaW5fQVNDcyxzaXplPTAuMSwgYmlucz03KSArIHNjYWxlX3hfbG9nMTAoYnJlYWtzPTEwXigtMTo0KSxsaW1pdHM9IGMoMC4xLCAxMDAwMCkpICArIGdlb21fYWJsaW5lKGludGVyY2VwdD0wLHNsb3BlPTAsY29sb3VyPSIjMDAwMDAwIixzaXplPTAuMikgICsgZ2VvbV92bGluZShkYXRhID0gRGF5bWVhbiwgYWVzKHhpbnRlcmNlcHQ9RGF5TWVhbiksY29sb3VyPU1lYW5fY29sb3Isc2l6ZT0wLjIsbGluZXR5cGU9ImRhc2hlZCIpICsgeWxpbSgtMSwxKSArIGZhY2V0X3dyYXAofkRheSwgbmNvbCA9IDEpICsgdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSksYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHZqdXN0PTEuMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTUpLHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSxwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSkgICtnZW9tX3BvaW50KGFlcyhncm91cE1lYW4sbG9nMkZvbGRDaGFuZ2UpLHNpemU9MS4wLCBkYXRhPWZfbWFya2VyTUFfaW5fQVNDcykKCmZmZmYKZ2dzYXZlKGZpbGU9IkRheUFsbF9kZW5zaXR5TUFwbG90X0FTQ3Bsb3R2c0FsbC5wZGYiLCBwbG90ID0gZmZmZiwgd2lkdGggPSA0LCBoZWlnaHQgPSA4LCBkcGkgPSAxMjApCgoKYGBgCgoKCgoKCgpgYGB7ciBsbGxsbGwgYWxsIHRpdGxlIG9uLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gMTJ9CgoKCgpmZmZmIDwtIHJlX3NlbGVjdF9wbG90ICAlPiUgbXV0YXRlKERheT1mYWN0b3IoRGF5LCBjKCJEYXkwIiwiRGF5NSIsIkRheTE0IikpKSAgJT4lICBnZ3Bsb3QoYWVzKHg9Z3JvdXBNZWFuLHk9bG9nMkZvbGRDaGFuZ2UpKSAgKyBzdGF0X2RlbnNpdHkyZChhZXMoZmlsbD0uLmRlbnNpdHkuLiksIGdlb20gPSAicmFzdGVyIixjb250b3VyID0gRkFMU0UpKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9IGRlbnNpdHlfY29sb3JfbG93LCBoaWdoID0gZGVuc2l0eV9jb2xvcl9oaWdoKSArIHNjYWxlX3hfbG9nMTAoKSAgKyBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0wLGNvbG91cj0iIzAwMDAwMCIsc2l6ZT0wLjIpICArIGdlb21fdmxpbmUoZGF0YSA9IERheW1lYW4sIGFlcyh4aW50ZXJjZXB0PURheU1lYW4pLGNvbG91cj1NZWFuX2NvbG9yLHNpemU9MC4yLGxpbmV0eXBlPSJkYXNoZWQiKSArIGdlb21fZGVuc2l0eTJkKGNvbG9yPSIjZmYwMDAwIixkYXRhPWZfbWFya2VyTUFfaW5fQVNDcyxzaXplPTAuMSwgYmlucz03KSArZ2VvbV9wb2ludChhZXMoZ3JvdXBNZWFuLGxvZzJGb2xkQ2hhbmdlLGNvbG9yPWNsdXN0ZXIpLHNpemU9MS4wLCBkYXRhPWZfbWFya2VyTUFfaW4pICsgeWxpbSgtMSwxKSArIGZhY2V0X3dyYXAofkRheSwgbmNvbCA9IDEpICsgdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSksYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LHZqdXN0PTEuMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIHN0cmlwLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTUpLHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSxwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSkgICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNmZjAwMDAiLCIjMDAwMGZmIiwiIzAwMDAwMCIpKSArIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBsYWJlbF90ZXh0KSwgc2VnbWVudC5jb2xvciA9ICIjMDAwMDAwIiwgc2VnbWVudC5zaXplID0gMC4xKSAKCgpmZmZmCmdnc2F2ZShmaWxlPSJEYXlBbGxfZGVuc2l0eU1BcGxvdF9TQ3NfdGl0bGUucGRmIiwgcGxvdCA9IGZmZmYsIHdpZHRoID0gNiwgaGVpZ2h0ID0gMTIsIGRwaSA9IDEyMCkKCmBgYAoKbWtkZTJkIDwtIE1BU1M6OmtkZTJkKHJlX3NlbGVjdF9wbG90JGdyb3VwTWVhbixyZV9zZWxlY3RfcGxvdCRsb2cyRm9sZENoYW5nZSxsaW1zID0gYyhjKDAuMSwgMTAwMDApLCByYW5nZSgtMSwxKSkpCgoKLS0tLS0tLS0tLS0KCiMjIG5vdG1fcGxvdGxpc3RfY3V0b2ZmIDEwLjAg44KSIOOCr+ODqeOCueOCv+ODquODs+OCsAoxOTEyMDTkvZzmiJAK5Lul5YmN44Gu44KC44Gu44KS5L+u5q2j44GX44Gm5L2c5oiQCgojIyMjIDTjgaTjga7jgq/jg6njgrnjgr/jg7zjgavliIbjgZHjgosgKHdpdGggRGF5MCwgRGF5NSwgRGF5MTQsIFNLTSAmIENUWOOBruOBvywga21lYW5zKQoKIyMgQ2x1c3RlcmluZyAoYWxsIGdlbmVzKQoKY2x1c3RlcmluZyBIMy4zCgpgYGB7ciBjbHVzdGVyaW5nIGN1ZmYgb2ZmIGdlbmVzIGtlbWFucywgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KIzIwMTkxMjA15L+u5q2j44Go5L2c5oiQCgpkZWZfbGlzdF9zZWxlY3QgPC0gZGVmICU+JSBmaWx0ZXIoc2FtcGxlICVpbiUgc29ydF9tb3VzZSkKCmNsdXN0ZXJfbnVtYmVyIDwtIDQKCmNzdmZpbGVwYXRoIDwtICJCUkIwNDM4cmVfbm91bWlfMTkwNTE1LUgzbW0xOEtPX0NUWCIKCgojIy0tLS0tLS0tLSBjbHVzdGVyaW5nIC0tLS0tLS0tLS0tIwpzZXQuc2VlZCgzKQoKIyBIMy4z44GnCiAKenNjb3JlX0JSQl9zIDwtIHpzY29yZV90eXBlICU+JSBkcGx5cjo6c2VsZWN0KCJlbnNfZ2VuZSIsYWxsX29mKGRlZl9saXN0X3NlbGVjdCRzYW1wbGUpKSAgJT4lIGZpbHRlcihhY3Jvc3Mod2hlcmUoaXNfZG91YmxlKSwgfiAoLnggIT0gMCl8KC54ID09IDApKSkgJT4lIGZpbHRlcihlbnNfZ2VuZSAlaW4lIG5vdG1fcGxvdGxpc3RfY3V0b2ZmJGVuc19nZW5lKQojenNjb3JlX0JSQl9zIDwtIHpzY29yZV9IM3AzICU+JSBmaWx0ZXIoYWNyb3NzKHdoZXJlKGlzX2RvdWJsZSksIH4gKC54ICE9IDApfCgueCA9PSAwKSkpCgpucm93KHpzY29yZV90eXBlKQpucm93KHpzY29yZV9CUkJfcykKClhzX2NsdXMgPC0genNjb3JlX0JSQl9zICU+JSBkcGx5cjo6c2VsZWN0KC1lbnNfZ2VuZSkgJT4lIGFzLm1hdHJpeCgpCnJvd25hbWVzKFhzX2NsdXMpIDwtIHpzY29yZV9CUkJfcyRlbnNfZ2VuZQoKa21fYWxsY3V0b2ZmIDwtIGttZWFucyhYc19jbHVzLGNsdXN0ZXJfbnVtYmVyLG5zdGFydCA9IDI1LGFsZ29yaXRobSA9ICJMbG95ZCIpCmttY19hbGxjdXRvZmYgPC0ga21fYWxsY3V0b2ZmJGNlbnRlcnMgJT4lIGFzX3RpYmJsZShyb3duYW1lcz0iY2x1c3RlciIpICU+JSBnYXRoZXIoc2FtcGxlLHZhbCwtY2x1c3RlcikgJT4lIGlubmVyX2pvaW4oZGVmX2xpc3Rfc2VsZWN0KQoKa21jX2FsbGN1dG9mZl9ncm91cCA8LSBrbWNfYWxsY3V0b2ZmCgoja21jX0xSVF9ncm91cCA8LSBrbWNfTFJUICU+JSBtdXRhdGUoZ3Jvd3RoPWZhY3Rvcihncm93dGgsIGMoIlVJIiwiRGlmZjBoIiwiRGlmZjI0aCIsIkRpZmY0OGgiKSkpICU+JSBtdXRhdGUodHlwZT1mYWN0b3IodHlwZSwgYygiRG94cGx1cyIsIkRveG1pbnVzIikpKQoKI2ttY19MUlRfZ3JvdXAgPC0ga21jX0xSVF9ncm91cCAlPiUgbXV0YXRlKHRpbWU9Y2FzZV93aGVuKGdyb3d0aD09IlVJIiB+IlVJIixncm93dGg9PSJEaWZmMGgifiIwaCIsZ3Jvd3RoPT0iRGlmZjI0aCJ+IjI0aCIsZ3Jvd3RoPT0iRGlmZjQ4aCJ+IjQ4aCIsVFJVRX4iZXJyb3IiKSkKI2ttY19MUlRfZ3JvdXAgPC0ga21jX0xSVF9ncm91cCAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwiMGgiLCIyNGgiLCI0OGgiKSkpCgojZ2dnZ2xhYmVsIDwtIHBhc3RlKCJrLW1lYW5zOiBUb3RhbCIsbnJvdyhYc19IM3AzKSwiWzFdIixrbV9hbGxjdXRvZmYkc2l6ZVsxXSwiWzJdIixrbV9hbGxjdXRvZmYkc2l6ZVsyXSwiWzNdIixrbV9hbGxjdXRvZmYkc2l6ZVszXSwiWzRdIixrbV9hbGxjdXRvZmYkc2l6ZVs0XSwiWzVdIixrbV9hbGxjdXRvZmYkc2l6ZVs1XSwiWzZdIixrbV9hbGxjdXRvZmYkc2l6ZVs2XSxzZXA9IiAiKQoKZ2dnZ2xhYmVsIDwtIHBhc3RlKCJPcmlnaW5hbCIsbnJvdyh6c2NvcmVfdHlwZSksImstbWVhbnM6IFRvdGFsIixucm93KHpzY29yZV9CUkJfcyksIlsxXSIsa21fYWxsY3V0b2ZmJHNpemVbMV0sIlsyXSIsa21fYWxsY3V0b2ZmJHNpemVbMl0sIlszXSIsa21fYWxsY3V0b2ZmJHNpemVbM10sIls0XSIsa21fYWxsY3V0b2ZmJHNpemVbNF0sc2VwPSIgIikKCgojZ2dnZ2xhYmVsIDwtIHBhc3RlKCJPcmlnaW5hbCIsbnJvdyh6c2NvcmVfdHlwZSksImstbWVhbnM6IFRvdGFsIixucm93KHpzY29yZV9CUkJfcyksIlsxXSIsa21fYWxsY3V0b2ZmJHNpemVbMV0sIlsyXSIsa21fYWxsY3V0b2ZmJHNpemVbMl0sIlszXSIsa21fYWxsY3V0b2ZmJHNpemVbM10sIls0XSIsa21fYWxsY3V0b2ZmJHNpemVbNF0sIls1XSIsa21fYWxsY3V0b2ZmJHNpemVbNV0sIls2XSIsa21fYWxsY3V0b2ZmJHNpemVbNl0sc2VwPSIgIikKCiMtLS0tLS0tIHNpemUgLS0tLS0tLSMKCnByaW50KGttX2FsbGN1dG9mZiRzaXplKSAKCnJycmVzX2FsbGN1dG9mZiA8LSBrbV9hbGxjdXRvZmYkY2x1c3RlciAlPiUgdGliYmxlKGVuc19nZW5lPW5hbWVzKC4pLGNsdXN0ZXI9LikgJT4lIGxlZnRfam9pbiguLHpzY29yZV90eXBlKSAlPiUgYXJyYW5nZShjbHVzdGVyKSAlPiUgZHBseXI6OnNlbGVjdChlbnNfZ2VuZSxleHRfZ2VuZSxiaW90eXBlLGNocixjbHVzdGVyLGFsbF9vZihkZWZfbGlzdF9zZWxlY3Qkc2FtcGxlKSkKCmZpbGVfcGF0aCA8LSBwYXN0ZSgiLi9DbHVzdGVyaW5nX2N1dG9mZi8iLCBjc3ZmaWxlcGF0aCwgIl9rbWVhbnNfY2x1c3Rlci5jc3YiLHNlcD0iIikgCnJlYWRyOjp3cml0ZV9jc3YocnJyZXNfYWxsY3V0b2ZmLGZpbGVfcGF0aCkKCiMjLS0tLS0tLSBQQ0EgLS0tLS0tLSMKCnBjYWNsdXN0ZXJfc2F2ZSA8LSBwcmNvbXAoWHNfY2x1cykkeCAlPiUgYXNfdGliYmxlICU+JSBkcGx5cjo6c2VsZWN0KFBDMSxQQzIpICU+JSBtdXRhdGUoY2x1c3Rlcj1rbV9hbGxjdXRvZmYkY2x1c3RlcikgJT4lIGdncGxvdChhZXMoUEMxLFBDMixjb2xvdXI9ZmFjdG9yKGNsdXN0ZXIpKSkrZ2VvbV9wb2ludChzaXplPTEuNSxhbHBoYT0wLjYpK2Nvb3JkX2ZpeGVkKCkrdGhlbWVfbGluZWRyYXcoKStnZ3NjaTo6c2NhbGVfY29sb3JfZDMoImNhdGVnb3J5MjAiKQoKZmlsZV9wYXRoIDwtIHBhc3RlKCIuL0NsdXN0ZXJpbmdfY3V0b2ZmLyIsIGNzdmZpbGVwYXRoLCAiX2ttZWFuc19fcGNhY2x1c3Rlcl9QQzFQQzIucGRmIixzZXA9IiIpIApnZ3NhdmUocGxvdD1wY2FjbHVzdGVyX3NhdmUsZmlsZT1maWxlX3BhdGgsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDEyMCkKcHJpbnQocGNhY2x1c3Rlcl9zYXZlKQoKcGNhY2x1c3Rlcl9zYXZlIDwtIHByY29tcChYc19jbHVzKSR4ICU+JSBhc190aWJibGUgJT4lIGRwbHlyOjpzZWxlY3QoUEMxLFBDMykgJT4lIG11dGF0ZShjbHVzdGVyPWttX2FsbGN1dG9mZiRjbHVzdGVyKSAlPiUgZ2dwbG90KGFlcyhQQzEsUEMzLGNvbG91cj1mYWN0b3IoY2x1c3RlcikpKStnZW9tX3BvaW50KHNpemU9MS41LGFscGhhPTAuNikrY29vcmRfZml4ZWQoKSt0aGVtZV9saW5lZHJhdygpK2dnc2NpOjpzY2FsZV9jb2xvcl9kMygiY2F0ZWdvcnkyMCIpCgpmaWxlX3BhdGggPC0gcGFzdGUoIi4vQ2x1c3RlcmluZ19jdXRvZmYvIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zX19wY2FjbHVzdGVyX1BDMVBDMy5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PXBjYWNsdXN0ZXJfc2F2ZSxmaWxlPWZpbGVfcGF0aCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQpwcmludChwY2FjbHVzdGVyX3NhdmUpCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIENUWOOBqFNLTeOBruiJsuOCkuWIhuOBkeOBpuODl+ODreODg+ODiCAoMjAxOTEyMDQgdmVyKQprbWNfYWxsY3V0b2ZmX2dyb3VwX25ld2dyb3VwIDwtIGttY19hbGxjdXRvZmZfZ3JvdXAgJT4lIG11dGF0ZShXVF9LTz1mYWN0b3IoV1RfS08sIGMoIkgzbW0xOEtPIiwiV1QiKSkpICU+JSBtdXRhdGUoRGF5PWZhY3RvcihEYXksIGMoIkRheTAiLCJEYXk1IiwiRGF5MTQiKSkpICU+JSBtdXRhdGUoaW50YWN0X0NUWD1mYWN0b3IoaW50YWN0X0NUWCwgYygiQ1RYIiwiU0tNIikpKQprbWNfYWxsY3V0b2ZmX2dyb3VwX25ld2dyb3VwIDwtIGttY19hbGxjdXRvZmZfZ3JvdXBfbmV3Z3JvdXAgJT4lIG11dGF0ZShncm91cF9uZXc9cGFzdGUoV1RfS08saW50YWN0X0NUWCxEYXksc2VwPSJfIikpICU+JSBtdXRhdGUodHlwZV9uZXc9cGFzdGUoV1RfS08saW50YWN0X0NUWCxzZXA9Il8iKSkKa21jX2FsbGN1dG9mZl9ncm91cF9uZXdncm91cCA8LSBrbWNfYWxsY3V0b2ZmX2dyb3VwX25ld2dyb3VwICU+JSBtdXRhdGUodHlwZV9uZXc9ZmFjdG9yKHR5cGVfbmV3LCBjKCJXVF9DVFgiLCJIM21tMThLT19DVFgiLCJXVF9TS00iLCJIM21tMThLT19TS00iKSkpCgojLS0tLS0tLS0tLS0tLS0tLS0tIwpmX2NsdXN0ZXIgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZ3JvdXBfYnkoZ3JvdXBfbmV3LHR5cGVfbmV3LERheSxjbHVzdGVyKSAlPiUgc3VtbWFyaXNlKGF2Zz1tZWFuKHZhbCksc2U9c2QodmFsKS9zcXJ0KGxlbmd0aCh2YWwpKSkgJT4lIHVuZ3JvdXAoKQpwcmludChrbWNfYWxsY3V0b2ZmX2dyb3VwX25ld2dyb3VwICU+JSBncm91cF9ieShncm91cF9uZXcsdHlwZV9uZXcsRGF5KSAlPiUgc3VtbWFyaXNlKCkpCiMtLS0tLS0tIwoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgU0tNKGRheTAp44KCQ1RY44Go5ZCM44GY6Imy44Gn44OX44Ot44OD44OIICgyMDE5MTIwNCB2ZXIpCgojLS0tLS0tLS0tLS0tLS0tLS0tIwpmX2NsdXN0ZXIyIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwX25ldywgV1RfS08sIERheSwgY2x1c3RlcikgJT4lIHN1bW1hcmlzZShhdmc9bWVhbih2YWwpLHNlPXNkKHZhbCkvc3FydChsZW5ndGgodmFsKSkpICU+JSB1bmdyb3VwKCkKcHJpbnQoa21jX2FsbGN1dG9mZl9ncm91cF9uZXdncm91cCAlPiUgZ3JvdXBfYnkoZ3JvdXBfbmV3LCBXVF9LTywgRGF5KSAlPiUgc3VtbWFyaXNlKCkpCiMtLS0tLS0tIwoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIyBTS00g44GoIENUWCDjga7oibLjgpLliIbjgZHjgabooajnpLoKIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yNCxmYWNlPSJpdGFsaWMiKQoKY2x1c3Rlcl9zYXZlIDwtIGttY19hbGxjdXRvZmZfZ3JvdXBfbmV3Z3JvdXAgJT4lIGdncGxvdChhZXMoRGF5LHZhbCxncm91cD10eXBlX25ldyxjb2xvdXI9dHlwZV9uZXcpKStnZW9tX2xpbmUoc2l6ZT0xLGFlcyh4PURheSx5PWF2Zyxjb2xvdXI9dHlwZV9uZXcpLGRhdGE9Zl9jbHVzdGVyKStnZW9tX3BvaW50KHNpemU9MikrZmFjZXRfd3JhcCh+Y2x1c3RlciwxKSArdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTIwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjQpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICsgZ2d0aXRsZShnZ2dnbGFiZWwpCgpnZ3NhdmUocGxvdD1jbHVzdGVyX3NhdmUsZmlsZT0iLi9DbHVzdGVyaW5nX2N1dG9mZi9CUkIwNDM4cmVfREVHX2RheTVfMmd1bmZkcjBwMl9jdHhza21fa21lYW5zNF9fY2x1c3Rlcl90eXBlMV9fZmluYWxfZmluMjAwNTIzLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDQuNSwgIGRwaSA9IDEyMCkKcHJpbnQoY2x1c3Rlcl9zYXZlKQojLS0tLS0tLS0tLS0tLS0tLS0tIwoKY2x1c3Rlcl9zYXZlIDwtIGttY19hbGxjdXRvZmZfZ3JvdXBfbmV3Z3JvdXAgJT4lIGdncGxvdChhZXMoRGF5LHZhbCxncm91cD10eXBlX25ldyxjb2xvdXI9dHlwZV9uZXcpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdD0wLHNsb3BlPTAsbGluZXR5cGU9ImRhc2hlZCIsY29sb3VyPSJncmF5IikgKyBnZW9tX2xpbmUoc2l6ZT0xLGFlcyh4PURheSx5PWF2Zyxjb2xvdXI9dHlwZV9uZXcpLGRhdGE9Zl9jbHVzdGVyKStnZW9tX3BvaW50KHNpemU9MikrZmFjZXRfd3JhcCh+Y2x1c3RlciwxKSArdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTIwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjQpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICsgZ2d0aXRsZShnZ2dnbGFiZWwpCgpnZ3NhdmUocGxvdD1jbHVzdGVyX3NhdmUsZmlsZT0iLi9DbHVzdGVyaW5nX2N1dG9mZi9CUkIwNDM4cmVfREVHX2RheTVfMmd1bmZkcjBwMl9jdHhza21fa21lYW5zNF9fY2x1c3Rlcl90eXBlMV9fZmluYWxfZGFzaF9maW4yMDA1MjMucGRmIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNC41LCBkcGkgPSAxMjApCnByaW50KGNsdXN0ZXJfc2F2ZSkKIy0tLS0tLS0tLS0tLS0tLS0tLSMKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIyBTS03jgoJDVFjjgajlkIzjgZjoibLjgafooajnpLoKIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yNCxmYWNlPSJpdGFsaWMiKQoKY2x1c3Rlcl9zYXZlIDwtIGttY19hbGxjdXRvZmZfZ3JvdXBfbmV3Z3JvdXAgJT4lIGdncGxvdChhZXMoRGF5LHZhbCxncm91cD1XVF9LTyxjb2xvdXI9V1RfS08pKStnZW9tX2xpbmUoc2l6ZT0xLGFlcyh4PURheSx5PWF2Zyxjb2xvdXI9V1RfS08pLGRhdGE9Zl9jbHVzdGVyMikrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmNsdXN0ZXIsMSkgK3RoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0yMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0KSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSkgK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSArIGdndGl0bGUoZ2dnZ2xhYmVsKQoKZ2dzYXZlKHBsb3Q9Y2x1c3Rlcl9zYXZlLGZpbGU9Ii4vQ2x1c3RlcmluZ19jdXRvZmYvQlJCMDQzOHJlX0RFR19kYXk1XzJndW5mZHIwcDJfY3R4c2ttX2ttZWFuczRfX2NsdXN0ZXJfdHlwZTJfX2ZpbmFsX2ZpbjIwMDUyMy5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0LjUsICBkcGkgPSAxMjApCnByaW50KGNsdXN0ZXJfc2F2ZSkKIy0tLS0tLS0tLS0tLS0tLS0tLSMKCmNsdXN0ZXJfc2F2ZSA8LSBrbWNfYWxsY3V0b2ZmX2dyb3VwX25ld2dyb3VwICU+JSBnZ3Bsb3QoYWVzKERheSx2YWwsZ3JvdXA9V1RfS08sY29sb3VyPVdUX0tPKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0wLGxpbmV0eXBlPSJkYXNoZWQiLGNvbG91cj0iZ3JheSIpICtnZW9tX2xpbmUoc2l6ZT0xLGFlcyh4PURheSx5PWF2Zyxjb2xvdXI9V1RfS08pLGRhdGE9Zl9jbHVzdGVyMikrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmNsdXN0ZXIsMSkgK3RoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0yMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0KSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSkgK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSArIGdndGl0bGUoZ2dnZ2xhYmVsKQoKZ2dzYXZlKHBsb3Q9Y2x1c3Rlcl9zYXZlLGZpbGU9Ii4vQ2x1c3RlcmluZ19jdXRvZmYvQlJCMDQzOHJlX0RFR19kYXk1XzJndW5mZHIwcDJfY3R4c2ttX2ttZWFuczRfX2NsdXN0ZXJfdHlwZTJfX2ZpbmFsX2Rhc2hfZmluMjAwNTIzLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDQuNSwgIGRwaSA9IDEyMCkKcHJpbnQoY2x1c3Rlcl9zYXZlKQojLS0tLS0tLS0tLS0tLS0tLS0tIwoKYGBgCgoKYGBge3Igc2VxIGN1ZmYgb2ZmIGdlbmVzIGtlbWFucyBjbHVzdGVyfQp6X2N1dG9mZmNsdXMxIDwtIHJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGNsdXN0ZXI9PSIxIikgJT4lIGRwbHlyOjpyZW5hbWUoY3V0b2ZmY2x1cz1jbHVzdGVyKQp6X2N1dG9mZmNsdXMyIDwtIHJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGNsdXN0ZXI9PSIyIikgJT4lIGRwbHlyOjpyZW5hbWUoY3V0b2ZmY2x1cz1jbHVzdGVyKQp6X2N1dG9mZmNsdXMzIDwtIHJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGNsdXN0ZXI9PSIzIikgJT4lIGRwbHlyOjpyZW5hbWUoY3V0b2ZmY2x1cz1jbHVzdGVyKQp6X2N1dG9mZmNsdXM0IDwtIHJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGNsdXN0ZXI9PSI0IikgJT4lIGRwbHlyOjpyZW5hbWUoY3V0b2ZmY2x1cz1jbHVzdGVyKQojel9jdXRvZmZjbHVzNSA8LSBycnJlc19hbGxjdXRvZmYgJT4lIGZpbHRlcihjbHVzdGVyPT0iNSIpICU+JSBkcGx5cjo6cmVuYW1lKGN1dG9mZmNsdXM9Y2x1c3RlcikKI3pfY3V0b2ZmY2x1czYgPC0gcnJyZXNfYWxsY3V0b2ZmICU+JSBmaWx0ZXIoY2x1c3Rlcj09IjYiKSAlPiUgZHBseXI6OnJlbmFtZShjdXRvZmZjbHVzPWNsdXN0ZXIpCgpucm93KHJycmVzX2FsbGN1dG9mZikKbnJvdyh6X2N1dG9mZmNsdXMxKQpucm93KHpfY3V0b2ZmY2x1czIpCm5yb3coel9jdXRvZmZjbHVzMykKbnJvdyh6X2N1dG9mZmNsdXM0KQojbnJvdyh6X2N1dG9mZmNsdXM1KQojbnJvdyh6X2N1dG9mZmNsdXM2KQpucm93KHJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGlzLm5hKGNsdXN0ZXIpKSkKCmBgYAoKYGBge3IgY3V0b2ZmIGNsdXN0ZXIgaW4gU0MgbGlzdH0KCnJycmVzX2FsbGN1dG9mZiAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgbWFya2VyU0NzJGVuc19nZW5lKSAlPiUgbGVmdF9qb2luKG1hcmtlclNDcykgICU+JSBncm91cF9ieShjbHVzdGVyLGNsdXMpICU+JSBzdW1tYXJpc2UoY291bnQ9bigpLCBsaXN0PXBhc3RlKGV4dF9nZW5lLGNvbGxhcHNlID0gIiwgIikpCgpycnJlc19hbGxjdXRvZmYgJT4lIGZpbHRlcihlbnNfZ2VuZSAlaW4lIG1hcmtlclNDcyRlbnNfZ2VuZSkgJT4lIGxlZnRfam9pbihtYXJrZXJTQ3MpICAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgZmMkZW5zX2dlbmUpICU+JSBncm91cF9ieShjbHVzdGVyLGNsdXMpICU+JSBzdW1tYXJpc2UoY291bnQ9bigpLCBsaXN0PXBhc3RlKGV4dF9nZW5lLGNvbGxhcHNlID0gIiwgIikpCgpycnJlc19hbGxjdXRvZmYgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIk15aDMiLCJDa20iLCJBY3RhMSIsIlRubnQyIiwiQWN0YiIsIkNzcnAzIiwiVHBtMiIsIk5zZGhsIiwiTXlvZyIsIlR0biIpKSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShjb3VudD1uKCksIGxpc3Q9cGFzdGUoZXh0X2dlbmUsY29sbGFwc2UgPSAiLCAiKSkKCiNycnJlc19hbGxjdXRvZmYgJT4lIGZpbHRlcihlbnNfZ2VuZSAlaW4lIGZjJGVuc19nZW5lKSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShjb3VudD1uKCksIGxpc3Q9cGFzdGUoZXh0X2dlbmUsY29sbGFwc2UgPSAiLCAiKSkgI0RFRzxEYXk1PuOBrumBuuS8neWtkOOBruaVsAoKcnJyZXNfYWxsY3V0b2ZmICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBtYXJrZXJTQ3MkZW5zX2dlbmUpICU+JSBsZWZ0X2pvaW4obWFya2VyU0NzKSAgJT4lIGdyb3VwX2J5KGNsdXN0ZXIsY2x1cykgJT4lIHN1bW1hcmlzZShjb3VudD1uKCksIGxpc3Q9cGFzdGUoZXh0X2dlbmUsY29sbGFwc2UgPSAiLCAiKSkgJT4lIHJlYWRyOjp3cml0ZV9jc3YoIi4vQ2x1c3RlcmluZ19jdXRvZmYvSDNtbTdmaWcxbGlzdC5jc3YiKQoKcnJyZXNfYWxsY3V0b2ZmICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBjKCJNeWgzIiwiQ2ttIiwiQWN0YTEiLCJUbm50MiIsIkFjdGIiLCJDc3JwMyIsIlRwbTIiLCJOc2RobCIsIk15b2ciLCJUdG4iKSkgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSBzdW1tYXJpc2UoY291bnQ9bigpLCBsaXN0PXBhc3RlKGV4dF9nZW5lLGNvbGxhcHNlID0gIiwgIikpICAlPiUgcmVhZHI6OndyaXRlX2NzdigiLi9DbHVzdGVyaW5nX2N1dG9mZi9NeW9nZW5pY2xpc3QuY3N2IikKCgoKYGBgCgoKIyMjIyDjgq/jg6njgrnjgr/jg6rjg7PjgrAgKGN1dG9mZiBjbHVzdGVyIEFTQ3MpIOOBrue1kOaenOOCkkdPCgpBU0Nz44KS44Kv44Op44K544K/44O85q+O44GrR08KCjIwMjAuNC4yMSwgNy4xN+S/ruatoywgOC405L+u5q2j44CAdmVyCgpgYGB7ciBHTyBwYXJ0MSBMb2FkIGxpc3QgY3V0b2ZmIGNsdXN0ZXJ9CiMyMDIwMDQyMeS/ruatoyB2ZXIKIzIwMTkxMjA25L+u5q2jIHZlcgoKI3pfaGVhdF9sYWJlbF9vcmRlcl9jbHVzdGVyNiA8LSB6X2hlYXRfbGFiZWxfb3JkZXJfY2x1c3RlciAlPiUgZHBseXI6OnNlbGVjdChleHRfZ2VuZSxoZWF0bWFwX29yZGVyLE5vLGNsdXN0ZXJfNikgJT4lIG11dGF0ZShoZWF0bWFwX29yZGVyPWFzLmludGVnZXIoaGVhdG1hcF9vcmRlciksTm89YXMuaW50ZWdlcihObyksY2x1c3Rlcl82PWFzLmludGVnZXIoY2x1c3Rlcl82KSklPiUgYXJyYW5nZShoZWF0bWFwX29yZGVyKSAlPiUgbGVmdF9qb2luKCBkcGx5cjo6c2VsZWN0KHpfdGltZWRlZ19zLGVuc19nZW5lLGV4dF9nZW5lLGJpb3R5cGUsY2hyKSkKI19fX19fX19fX19fX18jCgojIyB6X2hlYXRfbGFiZWxfb3JkZXJfY2x1c3RlciDjgavjgq/jg6njgrnjgr/jg7znlarlj7fjgYzlhaXjgaPjgabjgYTjgosKCgoKI3RhYmxlX2RlZ2NsdXN0ZXIgPC0gcnJyZXNfYWxsY3V0b2ZmICAlPiUgZl9BU0NzICU+JSBmaWx0ZXIoIWlzLm5hKGNsdXN0ZXIpKSAlPiUgYXJyYW5nZShjbHVzdGVyLCBlbnNfZ2VuZSkgJT4lIHVuaXF1ZSgpICU+JSBmaWx0ZXIoIWlzLm5hKGVuc19nZW5lKSkKCnRhYmxlX2RlZ2NsdXN0ZXIgPC0gcnJyZXNfYWxsY3V0b2ZmICAgJT4lIGZpbHRlcihlbnNfZ2VuZSAlaW4lIG1hcmtlclNDcyRlbnNfZ2VuZSkgJT4lIGZpbHRlcighaXMubmEoY2x1c3RlcikpICU+JSBhcnJhbmdlKGNsdXN0ZXIsIGVuc19nZW5lKSAlPiUgdW5pcXVlKCkgJT4lIGZpbHRlcighaXMubmEoZW5zX2dlbmUpKQoKZGVnY2x1c2dlbmUgPC0gdGFibGVfZGVnY2x1c3RlciAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShzaXplPW4oKSkgJT4lIG11dGF0ZShjbHVzdGVyPXJvd19udW1iZXIoKSkKCnRhYmxlX2RlZ2NsdXN0ZXIgPC0gdGFibGVfZGVnY2x1c3RlciAlPiUgbGVmdF9qb2luKGRlZ2NsdXNnZW5lICU+JSBkcGx5cjo6c2VsZWN0KGNsdXN0ZXIpKSAlPiUgYXJyYW5nZShjbHVzdGVyLGVuc19nZW5lKQoKZGVnY2x1c2dlbmUKIyMjIyMgRkRSIHNldHRpbmcgIyMjIyMjCmdvZmRyIDwtIDAuMQoKI2NsdXN0ZXJfbnVtIDwtIDYKY2x1c3Rlcl9udW0gPC0gbnJvdyhkZWdjbHVzZ2VuZSkKCmBgYAoKYGBge3IgZ28gcGFydDIgY2x1c3RlclByb2ZpbGUgY3V0b2ZmIGNsdXN0ZXJ9CiMgMjAxOTEyMDbkv67mraMKCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KG9yZy5NbS5lZy5kYikKCmZvbGRlcl9wYXRoIDwtICIuL0NsdXN0ZXJpbmdfY3V0b2ZmL2NsdXN0ZXJQcm9maWxlLyIKCiMtLS0tLS0tLS0tLS0tIwpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX3BhdGgsICJHT19jdXRvZmZjbHVzdGVyX1NLTW1hcmtlcl9CUGZkcjBwMV9nZW5lcmF0aW8iLHNlcD0iIikKI2ZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfcGF0aCwgIkdPX2N1dG9mZmNsdXN0ZXJfQVNDc19CUGZkcjBwMV9nZW5lcmF0aW8iLHNlcD0iIikKZmlsZW5hbWVfY3N2IDwtIGZpbGVfcGF0aAoKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLCAiR09fY3V0b2ZmY2x1c3Rlcl9TS01tYXJrZXJfQlBmZHIwcDFfZ2VuZXJhdGlvX2NsdXN0ZXIiLHNlcD0iIikKI2ZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfcGF0aCwgIkdPX2N1dG9mZmNsdXN0ZXJfQVNDc19CUGZkcjBwMV9nZW5lcmF0aW9fY2x1c3RlciIsc2VwPSIiKQpmaWxlbmFtZV9saXN0IDwtIGZpbGVfcGF0aAoKcHJpbnQoZmlsZW5hbWVfbGlzdCkKcHJpbnQoZmlsZW5hbWVfY3N2KQoKI+S+iyBmaWxlbmFtZV9saXN0IDwtICIuL0xSVC9jbHVzdGVyUHJvZmlsZS9IM21tMThLT19tb3VzZUNUWF9CUkIwNDM4X2RheTVfMmd1bmZkcjBwMl9rbWVhbnNfQlBmZHIwcDFfZ2VuZXJhdGlvX2NsdXN0ZXIiCiPkvosgZmlsZW5hbWVfY3N2IDwtICIuL0xSVC9jbHVzdGVyUHJvZmlsZS9IM21tMThLT19tb3VzZUNUWF9CUkIwNDM4X2RheTVfMmd1bmZkcjBwMl9rZW1hbnNfQlBmZHIwcDFfZ2VuZXJhdGlvIgojLS0tLS0tLS0tLS0tLSMKCmNsdXN0ZXJfbGlzdCA8LSBhcy5saXN0KE5BKSAj5Yid5pyf5YyWCgpmb3IgKGkgaW4gMTpjbHVzdGVyX251bSkgewogICBwcmVfbGlzdCA8LSBhcy5saXN0KE5BKQogICBwcmVfbGlzdCA8LSB0YWJsZV9kZWdjbHVzdGVyICU+JSBmaWx0ZXIoY2x1c3Rlcj09YXMuaW50ZWdlcihpKSkgJT4lIGRwbHlyOjpzZWxlY3QoZW5zX2dlbmUpICU+JSBhcy5saXN0KCkKICAgbmFtZXMocHJlX2xpc3QpIDwtIHBhc3RlKCJFTlNFTUJMIixhcy5jaGFyYWN0ZXIoaSksc2VwPSJfIikKIAogICBpZiAoaSA9PSAxKSB7IAogICAgIGNsdXN0ZXJfbGlzdCA8LSBwcmVfbGlzdAogICB9IAogICBlbHNlIGNsdXN0ZXJfbGlzdCA8LSBjKGNsdXN0ZXJfbGlzdCwgcHJlX2xpc3QpIAp9CgoKZm9yIChpIGluIDE6Y2x1c3Rlcl9udW0pIHsKICAgcHJpbnQocGFzdGUoaSwgY2x1c3Rlcl9saXN0W1tpXV0gJT4lIHRpYmJsZTo6ZW5mcmFtZShuYW1lID0gTlVMTCkgJT4lIG5yb3coKSwgc2VwPSIsICIpKQogIAogICBwcmVfZWdvX0JQIDwtIGVucmljaEdPKGdlbmUgPSBjbHVzdGVyX2xpc3RbW2ldXSwKICAgICAgICAgICAgICAgICBPcmdEYiA9ICJvcmcuTW0uZWcuZGIiLAogICAgICAgICAgICAgICAgIGtleVR5cGUgPSAnRU5TRU1CTCcsCiAgICAgICAgICAgICAgICAgb250ID0gIkJQIiwKICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgID0gZ29mZHIsIHF2YWx1ZUN1dG9mZiAgPSAxLjApIAogICAKICAgIzIwMTkxMjEx5L+u5q2jICBwdmFsdWVDdXRvZmYgID0gZmRyCiAgIAogICAjIyBwdmFsdWUgPCBxdmFsdWUgPCBwLmFkanVzdCAjIwogICAjIHF2YWx1ZUN1dG9mZiAgPSAwLjMgIHF2YWx1ZUN1dG9mZiAgPSAwLjIgLCBxdmFsdWVDdXRvZmYgID0gMS4wCgogICAjaWYgKGkgPT0gMSkgeyAKICAjICAgdGFibGVfZWdvX0JQIDwtIGRhdGEuZnJhbWUocHJlX2Vnb19CUCkgJT4lIG11dGF0ZShjbHVzdGVyPWFzLmludGVnZXIoaSkpCiAgIyAgICMg44Oq44K544OI5Z6L44GL44KJ44OH44O844K/44OV44Os44O844Og44G45aSJ5o+bCiAgICN9IAogICAjZWxzZSB0YWJsZV9lZ29fQlAgPC0gdGFibGVfZWdvX0JQICU+JSBiaW5kX3Jvd3MoZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9YXMuaW50ZWdlcihpKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgaWYgKGkgPT0gMSkgeyAKICAgICB0YWJsZV9lZ29fQlAgPC0gZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9cGFzdGUoImNsdXN0ZXIiLGFzLmNoYXJhY3RlcihpKSxzZXA9IiIpKSAgIyDjg6rjgrnjg4jlnovjgYvjgonjg4fjg7zjgr/jg5Xjg6zjg7zjg6DjgbjlpInmj5sKICAgfSAKICAgZWxzZSB0YWJsZV9lZ29fQlAgPC0gdGFibGVfZWdvX0JQICU+JSBiaW5kX3Jvd3MoZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9cGFzdGUoImNsdXN0ZXIiLGFzLmNoYXJhY3RlcihpKSxzZXA9IiIpKSkKICAgCiAgICMtLS0tIHBsb3QgLS0tIwogICAjQlBwbG90IDwtIGRvdHBsb3QocHJlX2Vnb19CUCwgc2hvd0NhdGVnb3J5PTMwLCBvcmRlckJ5ID0gIkNvdW50IikgI2NsdXN0ZXJQcm9maWxlIOOBruapn+iDveOBp+Wbs+OCkuaPj+OBjygxOTExMDbkv67mraMpIHdyb25nIG9yZGVyQnkgcGFyYW1ldGVyOyBzZXQgdG8gZGVmYXVsdCBgb3JkZXJCeSA9ICJ4ImAKICAgI3ByaW50KEJQcGxvdCkKICAgI2dnc2F2ZShCUHBsb3QsZmlsZT1wYXN0ZShmaWxlbmFtZV9saXN0LGFzLmNoYXJhY3RlcihpKSwiLnBuZyIsc2VwPSIiKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIsIGRwaSA9IDEyMCkKICAgI2dnc2F2ZShCUHBsb3QsZmlsZT1wYXN0ZShmaWxlbmFtZV9saXN0LGFzLmNoYXJhY3RlcihpKSwiLnBkZiIsc2VwPSIiKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIsIGRwaSA9IDEyMCkKfQoKcHJpbnQodGFibGVfZWdvX0JQICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgc3VtbWFyaXNlKCkpCgojLS0tLS0tIwojIOODh+ODvOOCv+OBr3RhYmxlX2Vnb19CUOOBq+OAggoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKIyDjg4bjg7zjg5bjg6vjgpLkv53lrZgKIyB0YWJsZV9lZ29fQlBfM3QzX0xSVDIgPC0gdGFibGVfZWdvX0JQCiMKdGFibGVfZWdvX0JQMSA8LSB0YWJsZV9lZ29fQlAgJT4lIG11dGF0ZShjbHVzdGVyPWZhY3RvcihjbHVzdGVyLGMoImNsdXN0ZXIxIiwiY2x1c3RlcjIiLCJjbHVzdGVyMyIsImNsdXN0ZXI0IikpKSAlPiUgYXJyYW5nZShjbHVzdGVyLGRlc2MoQ291bnQpKSAjMTkxMTA2KDIwMDQxNSksIDIwMDgzMSDkv67mraMgCgojdGFibGVfZWdvX0JQMSA8LSB0YWJsZV9lZ29fQlAgJT4lIGFycmFuZ2UoY2x1c3RlcixkZXNjKENvdW50KSkgICU+JSBsZWZ0X2pvaW4oZHBseXI6OnNlbGVjdChkZWdjbHVzZ2VuZSwgY2x1c3RlcikpICMxOTExMDYoMjAwNDE1KQoKcmVhZHI6OndyaXRlX2Nzdih0YWJsZV9lZ29fQlAxLHBhc3RlKGZpbGVuYW1lX2NzdiwiLmNzdiIsc2VwPSIiKSkKCmBgYAoKYGBge3IgZ28gcGFydDItMiBjbHVzdGVyUHJvZmlsZSBjdXRvZmYgY2x1c3Rlcn0KCnRhYmxlX2Vnb19CUDEgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSBzdW1tYXJpc2UoR090ZXJtX2NvdW50PW4oKSkKCiMg5YWI44Gu44OG44O844OW44Or44GuZ2VuZUlE44KSZ2VuZSBuYW1l44Gr572u5o+b44GZ44KL44CCKDIwMTkxMDI1KQoKdGFibGVnbyA8LSB0YWJsZV9lZ29fQlAxICU+JSBtdXRhdGUoZ2VuZV9uYW1lPWdlbmVJRCkgJT4lIGRwbHlyOjpzZWxlY3QoLShxdmFsdWUpKQoKZm9yIChpIGluIDE6bnJvdyh0YWJsZV9kZWdjbHVzdGVyKSkgewogIHRhYmxlZ28gPC0gdGFibGVnbyAlPiUgbXV0YXRlKGdlbmVfbmFtZT1nc3ViKGdlbmVfbmFtZSwgcGF0dGVybj10YWJsZV9kZWdjbHVzdGVyJGVuc19nZW5lW2ldLCByZXBsYWNlbWVudD10YWJsZV9kZWdjbHVzdGVyJGV4dF9nZW5lW2ldLCBpZ25vcmUuY2FzZSA9IFRSVUUpKQp9CgojcHJpbnQodGFibGVnbykKCiNyZWFkcjo6d3JpdGVfY3N2KHRhYmxlZ28scGFzdGUoZmlsZW5hbWVfY3N2LCJfZ2VuZW5hbWUuY3N2IixzZXA9IiIpKQoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKCgpgYGAKCgpgYGB7ciBHTyBzYXZlfQoKcmVhZHI6OndyaXRlX2Nzdih0YWJsZWdvLHBhc3RlKGZpbGVuYW1lX2NzdiwiX2dlbmVuYW1lLmNzdiIsc2VwPSIiKSkKCmBgYAoKU0tNIG1hcmtlcgoKYGBge3Igbm9ybWNvdW50IGZpZyBlcnJvciB2YXIgJiBib3hwbG90IDE5MDcyMi0xMjAzIFNLTXN9CgojPT09PT09PT0gQ2hhbmdlIGV2ZXJ5IGRhdGEg44GT44GT44Gn6aCG55Wq44KS5aSJ5pu0ID09PT09PT09IwoKdGJsIDwtIG5vcm1fcGxvdGxpc3RfYWxsICU+JSAgZmlsdGVyKGVuc19nZW5lICVpbiUgdGFibGVfZGVnY2x1c3RlciRlbnNfZ2VuZSkgJT4lIGFubm90YXRlKCkgICU+JSBtdXRhdGUoZXh0X2dlbmU9ZmFjdG9yKGV4dF9nZW5lLHRhYmxlX2RlZ2NsdXN0ZXIkZXh0X2dlbmUpKSAKCiN0YmwyIDwtIG5vcm1fcGxvdGxpc3RfYWxsICAlPiUgaW5uZXJfam9pbihlMmcsIGJ5ID0gImVuc19nZW5lIikgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIkFjdGExIiwiVHBtMiIpKQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCgpmX2dlbmVfbm9ybSA8LSBmdW5jdGlvbih4KSB4ICU+JSBncm91cF9ieShXVF9LTyxEYXksaW50YWN0X0NUWCxlbnNfZ2VuZSxleHRfZ2VuZSkgJT4lIHN1bW1hcmlzZShhdmc9bWVhbihub3JtYWxpemVkKSxzZT1zZChub3JtYWxpemVkKS9zcXJ0KGxlbmd0aChub3JtYWxpemVkKSkpICU+JSB1bmdyb3VwKCkKCiMtLS0tIwp0YmwgJT4lIGdyb3VwX2J5KFdUX0tPLERheSxpbnRhY3RfQ1RYKSAlPiUgc3VtbWFyaXNlKCkKIy0tLS0jCgojZmFjZT0iaXRhbGljIgoKIyMjIHBvaW50ICMjIwpnZ2dnZ3BwIDwtZ2dwbG90KHRibCxhZXMoRGF5LG5vcm1hbGl6ZWQsY29sb3VyPVdUX0tPLGdyb3VwPVdUX0tPKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiLG5jb2w9OSkrZ2VvbV9saW5lKHNpemU9MS4wLCBhZXMoeD1EYXkseT1hdmcsY29sb3VyPVdUX0tPKSxkYXRhPWZfZ2VuZV9ub3JtKSt0aGVtZV9idygpICsgeWxpbSgwLE5BKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTE2KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsZmFjZT0iaXRhbGljIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNikpK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKQpnZ3NhdmUoZmlsZT0iLi9DbHVzdGVyaW5nX2N1dG9mZi9jbHVzdGVyUHJvZmlsZS9ub3JtQ291bnRfU0tNbWFya2VyLnBkZiIsIHBsb3QgPSBnZ2dnZ3BwLCB3aWR0aD0yMiwgaGVpZ2h0PTEwLCBsaW1pdHNpemUgPSBGQUxTRSkKI3ByaW50KGdnZ2dncHApCgoKCmBgYAoKYGBge3Igbm9ybWNvdW50IGZpZyBlcnJvciB2YXIgJiBib3hwbG90IDE5MDcyMi0xMjAzIG15b30KCiM9PT09PT09PSBDaGFuZ2UgZXZlcnkgZGF0YSDjgZPjgZPjgafpoIbnlarjgpLlpInmm7QgPT09PT09PT0jCgp0YmwgPC0gbm9ybV9wbG90bGlzdF9hbGwgICU+JSBhbm5vdGF0ZSgpICU+JSAgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiTXloMyIsIkNrbSIsIkFjdGExIiwiVG5udDIiLCJBY3RiIiwiQ3NycDMiLCJUcG0yIiwiTnNkaGwiLCJNeW9nIiwiVHRuIikpIAojdGJsMiA8LSBub3JtX3Bsb3RsaXN0X2FsbCAgJT4lIGlubmVyX2pvaW4oZTJnLCBieSA9ICJlbnNfZ2VuZSIpICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBjKCJBY3RhMSIsIlRwbTIiKSkKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwoKZl9nZW5lX25vcm0gPC0gZnVuY3Rpb24oeCkgeCAlPiUgZ3JvdXBfYnkoV1RfS08sRGF5LGludGFjdF9DVFgsZW5zX2dlbmUsZXh0X2dlbmUpICU+JSBzdW1tYXJpc2UoYXZnPW1lYW4obm9ybWFsaXplZCksc2U9c2Qobm9ybWFsaXplZCkvc3FydChsZW5ndGgobm9ybWFsaXplZCkpKSAlPiUgdW5ncm91cCgpCgojLS0tLSMKdGJsICU+JSBncm91cF9ieShXVF9LTyxEYXksaW50YWN0X0NUWCkgJT4lIHN1bW1hcmlzZSgpCiMtLS0tIwoKI2ZhY2U9Iml0YWxpYyIKCiMjIyBwb2ludCAjIyMKZ2dnZ2dwcCA8LWdncGxvdCh0YmwsYWVzKERheSxub3JtYWxpemVkLGNvbG91cj1XVF9LTyxncm91cD1XVF9LTykpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IixuY29sPTUpK2dlb21fbGluZShzaXplPTEuMCwgYWVzKHg9RGF5LHk9YXZnLGNvbG91cj1XVF9LTyksZGF0YT1mX2dlbmVfbm9ybSkrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpKStnZ3NjaTo6c2NhbGVfY29sb3JfbnBnKCkKZ2dzYXZlKGZpbGU9Ii4vQ2x1c3RlcmluZ19jdXRvZmYvY2x1c3RlclByb2ZpbGUvbm9ybUNvdW50X015by5wZGYiLCBwbG90ID0gZ2dnZ2dwcCwgd2lkdGg9MTAsIGhlaWdodD02LCBsaW1pdHNpemUgPSBGQUxTRSkKI3ByaW50KGdnZ2dncHApCgojK2dlb21fc21vb3RoKHNlPUZBTFNFKQoKYGBgCgrjgZPjgZPjgb7jgacgKDIwMjAwODA3KQoKCgojIyMjIDLnvqQg44Gu57WQ5p6c44KSR08KCjIwMjAuNC4yMSwgNy4xN+S/ruatoywgOC405L+u5q2jLCA4LjMx5L+u5q2jdmVyCgpgYGB7ciBHTyBwYXJ0Mi0xIExvYWQgbGlzdCBjdXRvZmYgY2x1c3Rlcn0KCgpyZXNVcERvd24gPC0gcmUgJT4lIGZpbHRlcihhc3BlY3Q9PSJncm91cDFfQ1RYX0RheTVfSDNtbTE4S09fdnNfV1QiKSAlPiUgbXV0YXRlKENsdXN0ZXJfdXBkb3duPWNhc2Vfd2hlbihsb2cyRm9sZENoYW5nZSA+MCB+ICJVcCIsIGxvZzJGb2xkQ2hhbmdlPDAgfiAiRG93biIpLGNsdXN0ZXI9Y2FzZV93aGVuKGxvZzJGb2xkQ2hhbmdlID4wIH4gYXMuaW50ZWdlcigiMSIpLCBsb2cyRm9sZENoYW5nZTwwIH4gYXMuaW50ZWdlcigiMiIpKSkKcmVzVXBEb3duICU+JSBncm91cF9ieShhc3BlY3QsIENsdXN0ZXJfdXBkb3duLCBjbHVzdGVyKSAlPiUgc3VtbWFyaXNlKG4oKSkKCnRhYmxlX2RlZ2NsdXN0ZXIgPC0gcmVzVXBEb3duICU+JSBhcnJhbmdlKGNsdXN0ZXIsIGVuc19nZW5lKSAlPiUgdW5pcXVlKCkgJT4lIGZpbHRlcighaXMubmEoZW5zX2dlbmUpKQoKZGVnY2x1c2dlbmUgPC0gdGFibGVfZGVnY2x1c3RlciAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShzaXplPW4oKSkgJT4lIG11dGF0ZShjbHVzdGVyPXJvd19udW1iZXIoKSkKCnRhYmxlX2RlZ2NsdXN0ZXIgPC0gdGFibGVfZGVnY2x1c3RlciAlPiUgbGVmdF9qb2luKGRlZ2NsdXNnZW5lICU+JSBkcGx5cjo6c2VsZWN0KGNsdXN0ZXIpKSAlPiUgYXJyYW5nZShjbHVzdGVyLGVuc19nZW5lKQoKZGVnY2x1c2dlbmUKIyMjIyMgRkRSIHNldHRpbmcgIyMjIyMjCmdvZmRyIDwtIDAuMQoKI2NsdXN0ZXJfbnVtIDwtIDYKY2x1c3Rlcl9udW0gPC0gbnJvdyhkZWdjbHVzZ2VuZSkKCmBgYAoKYGBge3IgZ28gcGFydDItMiAxIGNsdXN0ZXJQcm9maWxlIGN1dG9mZiBjbHVzdGVyfQojIDIwMTkxMjA25L+u5q2jCgpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuTW0uZWcuZGIpCgpmb2xkZXJfcGF0aCA8LSAiLi8yZ3VuL2NsdXN0ZXJQcm9maWxlLyIKCiMtLS0tLS0tLS0tLS0tIwpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX3BhdGgsICJHT18yZ3VuX0JQZmRyMHAxX2dlbmVyYXRpbyIsc2VwPSIiKQojZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLCAiR09fY3V0b2ZmY2x1c3Rlcl9BU0NzX0JQZmRyMHAxX2dlbmVyYXRpbyIsc2VwPSIiKQpmaWxlbmFtZV9jc3YgPC0gZmlsZV9wYXRoCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX3BhdGgsICJHT18yZ3VuX1NLTW1hcmtlcl9CUGZkcjBwMV9nZW5lcmF0aW9fY2x1c3RlciIsc2VwPSIiKQojZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLCAiR09fY3V0b2ZmY2x1c3Rlcl9BU0NzX0JQZmRyMHAxX2dlbmVyYXRpb19jbHVzdGVyIixzZXA9IiIpCmZpbGVuYW1lX2xpc3QgPC0gZmlsZV9wYXRoCgpwcmludChmaWxlbmFtZV9saXN0KQpwcmludChmaWxlbmFtZV9jc3YpCgoj5L6LIGZpbGVuYW1lX2xpc3QgPC0gIi4vTFJUL2NsdXN0ZXJQcm9maWxlL0gzbW0xOEtPX21vdXNlQ1RYX0JSQjA0MzhfZGF5NV8yZ3VuZmRyMHAyX2ttZWFuc19CUGZkcjBwMV9nZW5lcmF0aW9fY2x1c3RlciIKI+S+iyBmaWxlbmFtZV9jc3YgPC0gIi4vTFJUL2NsdXN0ZXJQcm9maWxlL0gzbW0xOEtPX21vdXNlQ1RYX0JSQjA0MzhfZGF5NV8yZ3VuZmRyMHAyX2tlbWFuc19CUGZkcjBwMV9nZW5lcmF0aW8iCiMtLS0tLS0tLS0tLS0tIwoKY2x1c3Rlcl9saXN0IDwtIGFzLmxpc3QoTkEpICPliJ3mnJ/ljJYKCmZvciAoaSBpbiAxOmNsdXN0ZXJfbnVtKSB7CiAgIHByZV9saXN0IDwtIGFzLmxpc3QoTkEpCiAgIHByZV9saXN0IDwtIHRhYmxlX2RlZ2NsdXN0ZXIgJT4lIGZpbHRlcihjbHVzdGVyPT1hcy5pbnRlZ2VyKGkpKSAlPiUgZHBseXI6OnNlbGVjdChlbnNfZ2VuZSkgJT4lIGFzLmxpc3QoKQogICBuYW1lcyhwcmVfbGlzdCkgPC0gcGFzdGUoIkVOU0VNQkwiLGFzLmNoYXJhY3RlcihpKSxzZXA9Il8iKQogCiAgIGlmIChpID09IDEpIHsgCiAgICAgY2x1c3Rlcl9saXN0IDwtIHByZV9saXN0CiAgIH0gCiAgIGVsc2UgY2x1c3Rlcl9saXN0IDwtIGMoY2x1c3Rlcl9saXN0LCBwcmVfbGlzdCkgCn0KCgpmb3IgKGkgaW4gMTpjbHVzdGVyX251bSkgewogICBwcmludChwYXN0ZShpLCBjbHVzdGVyX2xpc3RbW2ldXSAlPiUgdGliYmxlOjplbmZyYW1lKG5hbWUgPSBOVUxMKSAlPiUgbnJvdygpLCBzZXA9IiwgIikpCiAgCiAgIHByZV9lZ29fQlAgPC0gZW5yaWNoR08oZ2VuZSA9IGNsdXN0ZXJfbGlzdFtbaV1dLAogICAgICAgICAgICAgICAgIE9yZ0RiID0gIm9yZy5NbS5lZy5kYiIsCiAgICAgICAgICAgICAgICAga2V5VHlwZSA9ICdFTlNFTUJMJywKICAgICAgICAgICAgICAgICBvbnQgPSAiQlAiLAogICAgICAgICAgICAgICAgIHBBZGp1c3RNZXRob2QgPSAiQkgiLAogICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiAgPSBnb2ZkciwgcXZhbHVlQ3V0b2ZmICA9IDEuMCkgCiAgIAoKICAgIzIwMTkxMjEx5L+u5q2jICBwdmFsdWVDdXRvZmYgID0gZmRyCiAgIAogICAjIyBwdmFsdWUgPCBxdmFsdWUgPCBwLmFkanVzdCAjIwogICAjIHF2YWx1ZUN1dG9mZiAgPSAwLjMgIHF2YWx1ZUN1dG9mZiAgPSAwLjIgLCBxdmFsdWVDdXRvZmYgID0gMS4wCgogICAjaWYgKGkgPT0gMSkgeyAKICAjICAgdGFibGVfZWdvX0JQIDwtIGRhdGEuZnJhbWUocHJlX2Vnb19CUCkgJT4lIG11dGF0ZShjbHVzdGVyPWFzLmludGVnZXIoaSkpCiAgIyAgICMg44Oq44K544OI5Z6L44GL44KJ44OH44O844K/44OV44Os44O844Og44G45aSJ5o+bCiAgICN9IAogICAjZWxzZSB0YWJsZV9lZ29fQlAgPC0gdGFibGVfZWdvX0JQICU+JSBiaW5kX3Jvd3MoZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9YXMuaW50ZWdlcihpKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgaWYgKGkgPT0gMSkgeyAKICAgICB0YWJsZV9lZ29fQlAgPC0gZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9cGFzdGUoImNsdXN0ZXIiLGFzLmNoYXJhY3RlcihpKSxzZXA9IiIpKSAgIyDjg6rjgrnjg4jlnovjgYvjgonjg4fjg7zjgr/jg5Xjg6zjg7zjg6DjgbjlpInmj5sKICAgfSAKICAgZWxzZSB0YWJsZV9lZ29fQlAgPC0gdGFibGVfZWdvX0JQICU+JSBiaW5kX3Jvd3MoZGF0YS5mcmFtZShwcmVfZWdvX0JQKSAlPiUgbXV0YXRlKGNsdXN0ZXI9cGFzdGUoImNsdXN0ZXIiLGFzLmNoYXJhY3RlcihpKSxzZXA9IiIpKSkKICAgIAoKICAgIy0tLS0gcGxvdCAtLS0jICgyMDIwIDA4MzEg44Ko44Op44O844GM5Ye644KL44Gu44Gn44CB44OX44Ot44OD44OI44Gv6Zmk44GPKQogICAjQlBwbG90IDwtIGRvdHBsb3QocHJlX2Vnb19CUCwgc2hvd0NhdGVnb3J5PTMwLCBvcmRlckJ5ID0gIkNvdW50IikgI2NsdXN0ZXJQcm9maWxlIOOBruapn+iDveOBp+Wbs+OCkuaPj+OBjygxOTExMDbkv67mraMpIHdyb25nIG9yZGVyQnkgcGFyYW1ldGVyOyBzZXQgdG8gZGVmYXVsdCBgb3JkZXJCeSA9ICJ4ImAKICAgI3ByaW50KEJQcGxvdCkKICAgI3ByaW50KCItLSIpCiAgICNnZ3NhdmUoQlBwbG90LGZpbGU9cGFzdGUoZmlsZW5hbWVfbGlzdCxhcy5jaGFyYWN0ZXIoaSksIi5wbmciLHNlcD0iIiksIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyLCBkcGkgPSAxMjApCiAgICNwcmludCgiLS0iKQogICAjZ2dzYXZlKEJQcGxvdCxmaWxlPXBhc3RlKGZpbGVuYW1lX2xpc3QsYXMuY2hhcmFjdGVyKGkpLCIucGRmIixzZXA9IiIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMiwgZHBpID0gMTIwKQp9CgpwcmludCh0YWJsZV9lZ29fQlAgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSBzdW1tYXJpc2UoKSkKCiMtLS0tLS0jCiMg44OH44O844K/44GvdGFibGVfZWdvX0JQ44Gr44CCCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIOODhuODvOODluODq+OCkuS/neWtmAojIHRhYmxlX2Vnb19CUF8zdDNfTFJUMiA8LSB0YWJsZV9lZ29fQlAKIwp0YWJsZV9lZ29fQlAxIDwtIHRhYmxlX2Vnb19CUCAlPiUgbXV0YXRlKGNsdXN0ZXI9ZmFjdG9yKGNsdXN0ZXIsYygiY2x1c3RlcjEiLCJjbHVzdGVyMiIpKSkgJT4lIGFycmFuZ2UoY2x1c3RlcixkZXNjKENvdW50KSkgIzE5MTEwNigyMDA0MTUpLCAyMDA4MzEg5L+u5q2jIAoKI3RhYmxlX2Vnb19CUDEgPC0gdGFibGVfZWdvX0JQICU+JSBhcnJhbmdlKGNsdXN0ZXIsZGVzYyhDb3VudCkpICAlPiUgbGVmdF9qb2luKGRwbHlyOjpzZWxlY3QoZGVnY2x1c2dlbmUsIGNsdXN0ZXIpKSAjMTkxMTA2KDIwMDQxNSkKCnJlYWRyOjp3cml0ZV9jc3YodGFibGVfZWdvX0JQMSxwYXN0ZShmaWxlbmFtZV9jc3YsIi5jc3YiLHNlcD0iIikpCgoKdGFibGVfZWdvX0JQMSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcmlzZShHT3Rlcm1fY291bnQ9bigpKQoKIyDlhYjjga7jg4bjg7zjg5bjg6vjga5nZW5lSUTjgpJnZW5lIG5hbWXjgavnva7mj5vjgZnjgovjgIIoMjAxOTEwMjUpCgp0YWJsZWdvIDwtIHRhYmxlX2Vnb19CUDEgJT4lIG11dGF0ZShnZW5lX25hbWU9Z2VuZUlEKSAlPiUgZHBseXI6OnNlbGVjdCgtKHF2YWx1ZSkpCgpmb3IgKGkgaW4gMTpucm93KHRhYmxlX2RlZ2NsdXN0ZXIpKSB7CiAgdGFibGVnbyA8LSB0YWJsZWdvICU+JSBtdXRhdGUoZ2VuZV9uYW1lPWdzdWIoZ2VuZV9uYW1lLCBwYXR0ZXJuPXRhYmxlX2RlZ2NsdXN0ZXIkZW5zX2dlbmVbaV0sIHJlcGxhY2VtZW50PXRhYmxlX2RlZ2NsdXN0ZXIkZXh0X2dlbmVbaV0sIGlnbm9yZS5jYXNlID0gVFJVRSkpCn0KCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCnRhYmxlZ28gPC0gdGFibGVnbyAlPiUgbXV0YXRlKENsdXN0ZXI9Y2FzZV93aGVuKGNsdXN0ZXI9PSJjbHVzdGVyMSIgfiAiVXAiLCBjbHVzdGVyPT0iY2x1c3RlcjIiICB+ICJEb3duIikpCgpyZWFkcjo6d3JpdGVfY3N2KHRhYmxlZ28scGFzdGUoZmlsZW5hbWVfY3N2LCJfZ2VuZW5hbWUuY3N2IixzZXA9IiIpKQoKYGBgCgorKysrKysrKysrKysrKysrKysrKysrKysrCgptYWtlIHBsb3QKCgoKYGBge3IgbG9hZCBkYXRhIGFuZCBmaWx0ZXIgdG9wfQojIGZpbHRlciBHTyB0b3AgMjAyMDA1MjYgdmVyCiMg5ZCE44Kv44Op44K544K/44O844GuQ291bnQgKEdlbmUgUmF0aW8pIOOBjOmrmOOBhOOCguOBruOAgXAuYWRqdXN044GM5bCP44GV44GE44KC44Gu44CBcHZhbHVl44GM5bCP44GV44GE44KC44Gu44KS5Y+W44KK5Ye644GZ44CCCgojIDNUMyBUb3A1CiNmaWxlXzN0MyA8LSAiL2hvbWUvZ3Vlc3RBL283MDU3OGEvYWt1d2FrYWRvL2t1d2FrYWRvL0JSQlNlcS9IM21tMThfRG94XzA0MzJsYW5lMi9GaW5hbF9MYXN0X1JzZXJ2ZXJfMjAwODExL0xSVC9jbHVzdGVyUHJvZmlsZS9ERUdfZmRyMHAxX19CUkIwNDMybGFuZTJub3VtaV9IM21tMThfRG94X2ttZWFuc19CUGZkcjBwMV9nZW5lcmF0aW9fZ2VuZW5hbWUuY3N2IgojZmlsZV8zdDMgPC0gIi9ob21lL2FrdXdha2Fkby9tYWtlcGxvdF8xOHByb2plY3QvSW5wdXRmaWxlL0RFR19mZHIwcDFfX0JSQjA0MzJsYW5lMm5vdW1pX0gzbW0xOF9Eb3hfa21lYW5zX0JQZmRyMHAxX2dlbmVyYXRpb19nZW5lbmFtZS5jc3YiCmRhdGFtb3VzZV9yYW5rYWxsIDwtIHRhYmxlZ28gJT4lIGdyb3VwX2J5KENsdXN0ZXIpICU+JSBhcnJhbmdlKGRlc2MoQ291bnQpLCBwLmFkanVzdCwgcHZhbHVlKSAlPiUgbXV0YXRlKHJhbms9cm93X251bWJlcigpKQpkYXRhbW91c2UgPC0gZGF0YW1vdXNlX3JhbmthbGwgJT4lIGZpbHRlcihyYW5rPD0zMCkKCgpwcmludChkYXRhbW91c2UpCgpmaWxlbmFtZSA8LSBwYXN0ZSgiLi9PdXRwdXRmaWxlLyIsIlRvcDMwX18iLGJhc2VuYW1lKGZpbGVuYW1lX2NzdiksIi5jc3YiLHNlcD0iIikKcHJpbnQoZmlsZW5hbWUpCmRhdGFtb3VzZSAlPiUgcmVhZHI6OndyaXRlX2NzdihmaWxlbmFtZSkgCgpmaWxlbmFtZSA8LSBwYXN0ZSgiLi9PdXRwdXRmaWxlLyIsIlJhbmtBbGxfXyIsYmFzZW5hbWUoZmlsZW5hbWVfY3N2KSwiLmNzdiIsc2VwPSIiKQpwcmludChmaWxlbmFtZSkKZGF0YW1vdXNlX3JhbmthbGwgJT4lIHJlYWRyOjp3cml0ZV9jc3YoZmlsZW5hbWUpIAoKCmBgYAoKCiMgcGxvdCBtb3VzZUdPCuS4gOW6puOBq+aPj+eUuyDvvIjkvb/jgYjjgZ3jgYbvvIkKCmBgYHtyIHBsb3RmYWNldCB0YXRlIDNUMywgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDV9CgpwbG90X21vdXNlIDwtIGRhdGFtb3VzZSAlPiUgZHBseXI6Om11dGF0ZShHZW5lUmF0aW8xPUdlbmVSYXRpbykgJT4lIHRpZHlyOjpzZXBhcmF0ZShjb2w9R2VuZVJhdGlvMSxzZXA9Ii8iLGludG89YygiY291bnQiLCJCUF9nZW5lc2l6ZSIpKSAlPiUgbXV0YXRlKEJQX2dlbmVzaXplPWFzLmludGVnZXIoQlBfZ2VuZXNpemUpLEdlbmVfcmF0aW89Q291bnQvQlBfZ2VuZXNpemUpICU+JSBkcGx5cjo6c2VsZWN0KC1jb3VudCkKCgp4bWF4PTAuMjAwCnhtaW49MC4wNTAgI3htaW49MC4wODUKCiNhbGxfYnJlYWsgPC0gYygzLDYsOSwxMiwxNSwxOCkKYWxsX2JyZWFrIDwtIGMoMTAsMTUsMjAsMjUsMzAsMzUsNDApCnNvcnRfbW91c2VfYWxsIDwtIHBsb3RfbW91c2UgJT4lIGFycmFuZ2UoZGVzYyhyYW5rKSkKCmdnZ1UgPC0gcGxvdF9tb3VzZSAlPiUgYXJyYW5nZShkZXNjKHJhbmspKSAlPiUgbXV0YXRlKERlc2NyaXB0aW9uID1mYWN0b3IoRGVzY3JpcHRpb24sc29ydF9tb3VzZV9hbGwkRGVzY3JpcHRpb24pKSAlPiUgZ2dwbG90KGFlcyh4PUdlbmVfcmF0aW8sIHk9RGVzY3JpcHRpb24sIGZpbGw9cC5hZGp1c3QpKSArIGdlb21fcG9pbnQoYWVzKHNpemU9Q291bnQpLHNoYXBlID0gMjEpICsgc2NhbGVfc2l6ZV9hcmVhKGJyZWFrcz1hbGxfYnJlYWspICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsbGVnZW5kLmJveD0iaG9yaXpvbnRhbCIsc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSxsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMSksc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiICwgaGlnaCA9ICJibHVlIixsaW1pdHMgPSBjKDAsIDAuMSkpICsgeGxpbSh4bWluLHhtYXgpICsgZmFjZXRfd3JhcCh+Q2x1c3RlcixzY2FsZXMgPSAiZnJlZV95IixuY29sPTEpCgpnZ2dVMCA8LSBwbG90X21vdXNlICU+JSBhcnJhbmdlKGRlc2MocmFuaykpICU+JSBtdXRhdGUoRGVzY3JpcHRpb24gPWZhY3RvcihEZXNjcmlwdGlvbixzb3J0X21vdXNlX2FsbCREZXNjcmlwdGlvbikpICAlPiUgZ2dwbG90KGFlcyh4PUdlbmVfcmF0aW8sIHk9RGVzY3JpcHRpb24sIGZpbGw9cC5hZGp1c3QpKSArIGdlb21fcG9pbnQoYWVzKHNpemU9Q291bnQpLHNoYXBlID0gMjEpICsgc2NhbGVfc2l6ZV9hcmVhKGJyZWFrcz1hbGxfYnJlYWspICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsbGVnZW5kLmJveD0iaG9yaXpvbnRhbCIsc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiICwgaGlnaCA9ICJibHVlIixsaW1pdHMgPSBjKDAsIDAuMSkpICsgeGxpbSh4bWluLHhtYXgpICsgZmFjZXRfd3JhcCh+Q2x1c3RlcixzY2FsZXMgPSAiZnJlZV95IixuY29sPTEpCgpwcmludChnZ2dVKQpnZ3NhdmUoZ2dnVSxmaWxlPXBhc3RlKCIuL091dHB1dGZpbGUvIiwibW91c2VfQlJCMDQzOF9fY2x1c3RlckFsbF9Ub3AzMF9CUGZkcjBwMV9wbG90MS5wZGYiLHNlcD0iIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDE1LCBkcGkgPSAxMjAsbGltaXRzaXplID0gRkFMU0UpCnByaW50KGdnZ1UwKQpnZ3NhdmUoZ2dnVTAsZmlsZT1wYXN0ZSgiLi9PdXRwdXRmaWxlLyIsIm1vdXNlX0JSQjA0MzhfX2NsdXN0ZXJBbGxfVG9wMzBfQlBmZHIwcDFfcGxvdDFfbm9uZS5wZGYiLHNlcD0iIiksIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTIsIGRwaSA9IDEyMCxsaW1pdHNpemUgPSBGQUxTRSkKCgoKYGBgCgpgYGB7ciBNQXBsb3QgREVHc30KCmZfREVHX2luIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGZpbHRlcihwYWRqPDAuMikKZl9ERUdfb3V0IDwtIGZ1bmN0aW9uKHgpIHggJT4lIGZpbHRlcigoIShwYWRqPDAuMikpfGlzLm5hKHBhZGopKQoKcmVfc2VsZWN0X3Bsb3QgJT4lIGdyb3VwX2J5KGFzcGVjdCkgJT4lIHN1bW1hcmlzZShuKCkpCnJlX3NlbGVjdF9wbG90ICU+JSBmX0RFR19pbiAlPiUgZ3JvdXBfYnkoYXNwZWN0KSAlPiUgc3VtbWFyaXNlKG4oKSkKcmVfc2VsZWN0X3Bsb3QgJT4lIGZfREVHX291dCAlPiUgZ3JvdXBfYnkoYXNwZWN0KSAlPiUgc3VtbWFyaXNlKG4oKSkKCmdnbWFwbG90IDwtIHJlX3NlbGVjdF9wbG90ICAlPiUgIGdncGxvdChhZXMoZ3JvdXBNZWFuLGxvZzJGb2xkQ2hhbmdlKSkrZ2VvbV9wb2ludChzaXplPTAuMSwgYWxwaGEgPSAwLjUsZGF0YT1mX0RFR19vdXQsY29sb3I9IiNiZGJkYmQiKSArIGdlb21fYWJsaW5lKGludGVyY2VwdD0wLHNsb3BlPTAsY29sb3VyPSJibGFjayIsc2l6ZT0wLjIpICArIGdlb21fdmxpbmUoZGF0YSA9IERheW1lYW4sIGFlcyh4aW50ZXJjZXB0PURheU1lYW4pLGNvbG91cj1NZWFuX2NvbG9yLHNpemU9MC4yLGxpbmV0eXBlPSJkYXNoZWQiKSArZ2VvbV9wb2ludChhZXMoZ3JvdXBNZWFuLGxvZzJGb2xkQ2hhbmdlKSxzaXplPTAuMyxjb2xvcj0iIzAwMDBmZiIsIGRhdGE9Zl9ERUdfaW4pICsgc2NhbGVfeF9sb2cxMCgpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArIGdndGl0bGUoZ2dnZ2xhYmVsKSArIHlsaW0oLTUuMCwgNS4wKSArIGZhY2V0X3dyYXAofkRheSxuY29sPTEpICsgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSxheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsdmp1c3Q9MS4wKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0Iiwgc3RyaXAudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNSksc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSx0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgpKQoKIysgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNmZjAwMDAiLCIjMDAwMGZmIiwiIzAwMDAwMCIpKSAKCmdnc2F2ZShmaWxlPSIuLzJndW4vREVHX0RheUFsbF9NQXBsb3RfTWVhbi5wZGYiLCBwbG90ID0gZ2dtYXBsb3QsIHdpZHRoID0gNywgaGVpZ2h0ID0gOCwgZHBpID0gMTIwKQpwbG90KGdnbWFwbG90KQoKCmBgYAoK